From b9cd02937b358ae035ed554a28037237a6c8434c Mon Sep 17 00:00:00 2001 From: Michael Weghorn <m.weghorn@posteo.de> Date: Tue, 28 Sep 2021 15:55:43 +0200 Subject: qt5: Rename sources + headers according to new class names This renames the source and header files according to the new class names without a "5" in them, as mentioned in Change-Id: Idf422f82ca9dafbb70e9a64de9c8cfc4cc8c0909 (qt5: Remove "5" from class names in qt5 VCL plugin): > Renaming the headers and source files will be done > in a separate commit to make tracking git history easier. Change-Id: If955e77c8ba508d0a2e01e3a9df1be6dc04c4e4e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122806 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> --- vcl/CustomTarget_qt5_moc.mk | 22 +- vcl/Library_vclplug_qt5.mk | 62 +- vcl/inc/qt5/Qt5AccessibleEventListener.hxx | 38 - vcl/inc/qt5/Qt5AccessibleWidget.hxx | 159 --- vcl/inc/qt5/Qt5Bitmap.hxx | 61 -- vcl/inc/qt5/Qt5Clipboard.hxx | 97 -- vcl/inc/qt5/Qt5Data.hxx | 47 - vcl/inc/qt5/Qt5DragAndDrop.hxx | 115 --- vcl/inc/qt5/Qt5FilePicker.hxx | 176 ---- vcl/inc/qt5/Qt5Font.hxx | 43 - vcl/inc/qt5/Qt5FontFace.hxx | 76 -- vcl/inc/qt5/Qt5Frame.hxx | 228 ----- vcl/inc/qt5/Qt5Graphics.hxx | 247 ----- vcl/inc/qt5/Qt5GraphicsBase.hxx | 29 - vcl/inc/qt5/Qt5Graphics_Controls.hxx | 99 -- vcl/inc/qt5/Qt5Instance.hxx | 169 ---- vcl/inc/qt5/Qt5MainWindow.hxx | 40 - vcl/inc/qt5/Qt5Menu.hxx | 122 --- vcl/inc/qt5/Qt5Object.hxx | 81 -- vcl/inc/qt5/Qt5OpenGLContext.hxx | 50 - vcl/inc/qt5/Qt5Painter.hxx | 68 -- vcl/inc/qt5/Qt5Printer.hxx | 32 - vcl/inc/qt5/Qt5SvpGraphics.hxx | 54 - vcl/inc/qt5/Qt5SvpSurface.hxx | 44 - vcl/inc/qt5/Qt5System.hxx | 23 - vcl/inc/qt5/Qt5Timer.hxx | 49 - vcl/inc/qt5/Qt5Tools.hxx | 182 ---- vcl/inc/qt5/Qt5Transferable.hxx | 124 --- vcl/inc/qt5/Qt5VirtualDevice.hxx | 56 -- vcl/inc/qt5/Qt5Widget.hxx | 109 -- vcl/inc/qt5/Qt5XAccessible.hxx | 34 - vcl/inc/qt5/QtAccessibleEventListener.hxx | 38 + vcl/inc/qt5/QtAccessibleWidget.hxx | 159 +++ vcl/inc/qt5/QtBitmap.hxx | 61 ++ vcl/inc/qt5/QtClipboard.hxx | 97 ++ vcl/inc/qt5/QtData.hxx | 47 + vcl/inc/qt5/QtDragAndDrop.hxx | 115 +++ vcl/inc/qt5/QtFilePicker.hxx | 176 ++++ vcl/inc/qt5/QtFont.hxx | 43 + vcl/inc/qt5/QtFontFace.hxx | 76 ++ vcl/inc/qt5/QtFrame.hxx | 228 +++++ vcl/inc/qt5/QtGraphics.hxx | 247 +++++ vcl/inc/qt5/QtGraphicsBase.hxx | 29 + vcl/inc/qt5/QtGraphics_Controls.hxx | 99 ++ vcl/inc/qt5/QtInstance.hxx | 169 ++++ vcl/inc/qt5/QtMainWindow.hxx | 40 + vcl/inc/qt5/QtMenu.hxx | 122 +++ vcl/inc/qt5/QtObject.hxx | 81 ++ vcl/inc/qt5/QtOpenGLContext.hxx | 50 + vcl/inc/qt5/QtPainter.hxx | 68 ++ vcl/inc/qt5/QtPrinter.hxx | 32 + vcl/inc/qt5/QtSvpGraphics.hxx | 54 + vcl/inc/qt5/QtSvpSurface.hxx | 44 + vcl/inc/qt5/QtSystem.hxx | 23 + vcl/inc/qt5/QtTimer.hxx | 49 + vcl/inc/qt5/QtTools.hxx | 182 ++++ vcl/inc/qt5/QtTransferable.hxx | 124 +++ vcl/inc/qt5/QtVirtualDevice.hxx | 56 ++ vcl/inc/qt5/QtWidget.hxx | 109 ++ vcl/inc/qt5/QtXAccessible.hxx | 34 + vcl/qt5/Qt5AccessibleEventListener.cxx | 173 ---- vcl/qt5/Qt5AccessibleWidget.cxx | 1476 ---------------------------- vcl/qt5/Qt5Bitmap.cxx | 188 ---- vcl/qt5/Qt5Clipboard.cxx | 252 ----- vcl/qt5/Qt5Data.cxx | 337 ------- vcl/qt5/Qt5DragAndDrop.cxx | 252 ----- vcl/qt5/Qt5FilePicker.cxx | 945 ------------------ vcl/qt5/Qt5Font.cxx | 163 --- vcl/qt5/Qt5FontFace.cxx | 239 ----- vcl/qt5/Qt5Frame.cxx | 1452 --------------------------- vcl/qt5/Qt5Graphics.cxx | 106 -- vcl/qt5/Qt5Graphics_Controls.cxx | 1134 --------------------- vcl/qt5/Qt5Graphics_GDI.cxx | 757 -------------- vcl/qt5/Qt5Graphics_Text.cxx | 354 ------- vcl/qt5/Qt5Instance.cxx | 702 ------------- vcl/qt5/Qt5Instance_Print.cxx | 140 --- vcl/qt5/Qt5MainWindow.cxx | 47 - vcl/qt5/Qt5Menu.cxx | 702 ------------- vcl/qt5/Qt5Object.cxx | 157 --- vcl/qt5/Qt5OpenGLContext.cxx | 154 --- vcl/qt5/Qt5Painter.cxx | 57 -- vcl/qt5/Qt5Printer.cxx | 27 - vcl/qt5/Qt5SvpGraphics.cxx | 113 --- vcl/qt5/Qt5SvpSurface.cxx | 91 -- vcl/qt5/Qt5SvpVirtualDevice.hxx | 36 - vcl/qt5/Qt5System.cxx | 30 - vcl/qt5/Qt5Timer.cxx | 52 - vcl/qt5/Qt5Tools.cxx | 122 --- vcl/qt5/Qt5Transferable.cxx | 344 ------- vcl/qt5/Qt5VirtualDevice.cxx | 87 -- vcl/qt5/Qt5Widget.cxx | 842 ---------------- vcl/qt5/Qt5XAccessible.cxx | 29 - vcl/qt5/QtAccessibleEventListener.cxx | 173 ++++ vcl/qt5/QtAccessibleWidget.cxx | 1476 ++++++++++++++++++++++++++++ vcl/qt5/QtBitmap.cxx | 188 ++++ vcl/qt5/QtClipboard.cxx | 252 +++++ vcl/qt5/QtData.cxx | 337 +++++++ vcl/qt5/QtDragAndDrop.cxx | 252 +++++ vcl/qt5/QtFilePicker.cxx | 945 ++++++++++++++++++ vcl/qt5/QtFont.cxx | 163 +++ vcl/qt5/QtFontFace.cxx | 239 +++++ vcl/qt5/QtFrame.cxx | 1452 +++++++++++++++++++++++++++ vcl/qt5/QtGraphics.cxx | 106 ++ vcl/qt5/QtGraphics_Controls.cxx | 1134 +++++++++++++++++++++ vcl/qt5/QtGraphics_GDI.cxx | 757 ++++++++++++++ vcl/qt5/QtGraphics_Text.cxx | 354 +++++++ vcl/qt5/QtInstance.cxx | 702 +++++++++++++ vcl/qt5/QtInstance_Print.cxx | 140 +++ vcl/qt5/QtMainWindow.cxx | 47 + vcl/qt5/QtMenu.cxx | 702 +++++++++++++ vcl/qt5/QtObject.cxx | 157 +++ vcl/qt5/QtOpenGLContext.cxx | 154 +++ vcl/qt5/QtPainter.cxx | 57 ++ vcl/qt5/QtPrinter.cxx | 27 + vcl/qt5/QtSvpGraphics.cxx | 113 +++ vcl/qt5/QtSvpSurface.cxx | 91 ++ vcl/qt5/QtSvpVirtualDevice.hxx | 36 + vcl/qt5/QtSystem.cxx | 30 + vcl/qt5/QtTimer.cxx | 52 + vcl/qt5/QtTools.cxx | 122 +++ vcl/qt5/QtTransferable.cxx | 344 +++++++ vcl/qt5/QtVirtualDevice.cxx | 87 ++ vcl/qt5/QtWidget.cxx | 842 ++++++++++++++++ vcl/qt5/QtXAccessible.cxx | 29 + vcl/unx/kf5/KF5FilePicker.cxx | 2 +- vcl/unx/kf5/KF5FilePicker.hxx | 2 +- vcl/unx/kf5/KF5SalFrame.cxx | 2 +- vcl/unx/kf5/KF5SalFrame.hxx | 4 +- vcl/unx/kf5/KF5SalInstance.cxx | 2 +- vcl/unx/kf5/KF5SalInstance.hxx | 2 +- 130 files changed, 14261 insertions(+), 14261 deletions(-) delete mode 100644 vcl/inc/qt5/Qt5AccessibleEventListener.hxx delete mode 100644 vcl/inc/qt5/Qt5AccessibleWidget.hxx delete mode 100644 vcl/inc/qt5/Qt5Bitmap.hxx delete mode 100644 vcl/inc/qt5/Qt5Clipboard.hxx delete mode 100644 vcl/inc/qt5/Qt5Data.hxx delete mode 100644 vcl/inc/qt5/Qt5DragAndDrop.hxx delete mode 100644 vcl/inc/qt5/Qt5FilePicker.hxx delete mode 100644 vcl/inc/qt5/Qt5Font.hxx delete mode 100644 vcl/inc/qt5/Qt5FontFace.hxx delete mode 100644 vcl/inc/qt5/Qt5Frame.hxx delete mode 100644 vcl/inc/qt5/Qt5Graphics.hxx delete mode 100644 vcl/inc/qt5/Qt5GraphicsBase.hxx delete mode 100644 vcl/inc/qt5/Qt5Graphics_Controls.hxx delete mode 100644 vcl/inc/qt5/Qt5Instance.hxx delete mode 100644 vcl/inc/qt5/Qt5MainWindow.hxx delete mode 100644 vcl/inc/qt5/Qt5Menu.hxx delete mode 100644 vcl/inc/qt5/Qt5Object.hxx delete mode 100644 vcl/inc/qt5/Qt5OpenGLContext.hxx delete mode 100644 vcl/inc/qt5/Qt5Painter.hxx delete mode 100644 vcl/inc/qt5/Qt5Printer.hxx delete mode 100644 vcl/inc/qt5/Qt5SvpGraphics.hxx delete mode 100644 vcl/inc/qt5/Qt5SvpSurface.hxx delete mode 100644 vcl/inc/qt5/Qt5System.hxx delete mode 100644 vcl/inc/qt5/Qt5Timer.hxx delete mode 100644 vcl/inc/qt5/Qt5Tools.hxx delete mode 100644 vcl/inc/qt5/Qt5Transferable.hxx delete mode 100644 vcl/inc/qt5/Qt5VirtualDevice.hxx delete mode 100644 vcl/inc/qt5/Qt5Widget.hxx delete mode 100644 vcl/inc/qt5/Qt5XAccessible.hxx create mode 100644 vcl/inc/qt5/QtAccessibleEventListener.hxx create mode 100644 vcl/inc/qt5/QtAccessibleWidget.hxx create mode 100644 vcl/inc/qt5/QtBitmap.hxx create mode 100644 vcl/inc/qt5/QtClipboard.hxx create mode 100644 vcl/inc/qt5/QtData.hxx create mode 100644 vcl/inc/qt5/QtDragAndDrop.hxx create mode 100644 vcl/inc/qt5/QtFilePicker.hxx create mode 100644 vcl/inc/qt5/QtFont.hxx create mode 100644 vcl/inc/qt5/QtFontFace.hxx create mode 100644 vcl/inc/qt5/QtFrame.hxx create mode 100644 vcl/inc/qt5/QtGraphics.hxx create mode 100644 vcl/inc/qt5/QtGraphicsBase.hxx create mode 100644 vcl/inc/qt5/QtGraphics_Controls.hxx create mode 100644 vcl/inc/qt5/QtInstance.hxx create mode 100644 vcl/inc/qt5/QtMainWindow.hxx create mode 100644 vcl/inc/qt5/QtMenu.hxx create mode 100644 vcl/inc/qt5/QtObject.hxx create mode 100644 vcl/inc/qt5/QtOpenGLContext.hxx create mode 100644 vcl/inc/qt5/QtPainter.hxx create mode 100644 vcl/inc/qt5/QtPrinter.hxx create mode 100644 vcl/inc/qt5/QtSvpGraphics.hxx create mode 100644 vcl/inc/qt5/QtSvpSurface.hxx create mode 100644 vcl/inc/qt5/QtSystem.hxx create mode 100644 vcl/inc/qt5/QtTimer.hxx create mode 100644 vcl/inc/qt5/QtTools.hxx create mode 100644 vcl/inc/qt5/QtTransferable.hxx create mode 100644 vcl/inc/qt5/QtVirtualDevice.hxx create mode 100644 vcl/inc/qt5/QtWidget.hxx create mode 100644 vcl/inc/qt5/QtXAccessible.hxx delete mode 100644 vcl/qt5/Qt5AccessibleEventListener.cxx delete mode 100644 vcl/qt5/Qt5AccessibleWidget.cxx delete mode 100644 vcl/qt5/Qt5Bitmap.cxx delete mode 100644 vcl/qt5/Qt5Clipboard.cxx delete mode 100644 vcl/qt5/Qt5Data.cxx delete mode 100644 vcl/qt5/Qt5DragAndDrop.cxx delete mode 100644 vcl/qt5/Qt5FilePicker.cxx delete mode 100644 vcl/qt5/Qt5Font.cxx delete mode 100644 vcl/qt5/Qt5FontFace.cxx delete mode 100644 vcl/qt5/Qt5Frame.cxx delete mode 100644 vcl/qt5/Qt5Graphics.cxx delete mode 100644 vcl/qt5/Qt5Graphics_Controls.cxx delete mode 100644 vcl/qt5/Qt5Graphics_GDI.cxx delete mode 100644 vcl/qt5/Qt5Graphics_Text.cxx delete mode 100644 vcl/qt5/Qt5Instance.cxx delete mode 100644 vcl/qt5/Qt5Instance_Print.cxx delete mode 100644 vcl/qt5/Qt5MainWindow.cxx delete mode 100644 vcl/qt5/Qt5Menu.cxx delete mode 100644 vcl/qt5/Qt5Object.cxx delete mode 100644 vcl/qt5/Qt5OpenGLContext.cxx delete mode 100644 vcl/qt5/Qt5Painter.cxx delete mode 100644 vcl/qt5/Qt5Printer.cxx delete mode 100644 vcl/qt5/Qt5SvpGraphics.cxx delete mode 100644 vcl/qt5/Qt5SvpSurface.cxx delete mode 100644 vcl/qt5/Qt5SvpVirtualDevice.hxx delete mode 100644 vcl/qt5/Qt5System.cxx delete mode 100644 vcl/qt5/Qt5Timer.cxx delete mode 100644 vcl/qt5/Qt5Tools.cxx delete mode 100644 vcl/qt5/Qt5Transferable.cxx delete mode 100644 vcl/qt5/Qt5VirtualDevice.cxx delete mode 100644 vcl/qt5/Qt5Widget.cxx delete mode 100644 vcl/qt5/Qt5XAccessible.cxx create mode 100644 vcl/qt5/QtAccessibleEventListener.cxx create mode 100644 vcl/qt5/QtAccessibleWidget.cxx create mode 100644 vcl/qt5/QtBitmap.cxx create mode 100644 vcl/qt5/QtClipboard.cxx create mode 100644 vcl/qt5/QtData.cxx create mode 100644 vcl/qt5/QtDragAndDrop.cxx create mode 100644 vcl/qt5/QtFilePicker.cxx create mode 100644 vcl/qt5/QtFont.cxx create mode 100644 vcl/qt5/QtFontFace.cxx create mode 100644 vcl/qt5/QtFrame.cxx create mode 100644 vcl/qt5/QtGraphics.cxx create mode 100644 vcl/qt5/QtGraphics_Controls.cxx create mode 100644 vcl/qt5/QtGraphics_GDI.cxx create mode 100644 vcl/qt5/QtGraphics_Text.cxx create mode 100644 vcl/qt5/QtInstance.cxx create mode 100644 vcl/qt5/QtInstance_Print.cxx create mode 100644 vcl/qt5/QtMainWindow.cxx create mode 100644 vcl/qt5/QtMenu.cxx create mode 100644 vcl/qt5/QtObject.cxx create mode 100644 vcl/qt5/QtOpenGLContext.cxx create mode 100644 vcl/qt5/QtPainter.cxx create mode 100644 vcl/qt5/QtPrinter.cxx create mode 100644 vcl/qt5/QtSvpGraphics.cxx create mode 100644 vcl/qt5/QtSvpSurface.cxx create mode 100644 vcl/qt5/QtSvpVirtualDevice.hxx create mode 100644 vcl/qt5/QtSystem.cxx create mode 100644 vcl/qt5/QtTimer.cxx create mode 100644 vcl/qt5/QtTools.cxx create mode 100644 vcl/qt5/QtTransferable.cxx create mode 100644 vcl/qt5/QtVirtualDevice.cxx create mode 100644 vcl/qt5/QtWidget.cxx create mode 100644 vcl/qt5/QtXAccessible.cxx diff --git a/vcl/CustomTarget_qt5_moc.mk b/vcl/CustomTarget_qt5_moc.mk index 87caee8d918e..14360ae3ae26 100644 --- a/vcl/CustomTarget_qt5_moc.mk +++ b/vcl/CustomTarget_qt5_moc.mk @@ -10,17 +10,17 @@ $(eval $(call gb_CustomTarget_CustomTarget,vcl/qt5)) $(call gb_CustomTarget_get_target,vcl/qt5) : \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5AccessibleWidget.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Clipboard.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5FilePicker.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Frame.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Instance.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5MainWindow.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Menu.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Object.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Timer.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Widget.moc \ - $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5XAccessible.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtAccessibleWidget.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtClipboard.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtFilePicker.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtFrame.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtInstance.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtMainWindow.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtMenu.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtObject.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtTimer.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtWidget.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/QtXAccessible.moc \ $(call gb_CustomTarget_get_workdir,vcl/qt5)/%.moc : \ $(SRCDIR)/vcl/inc/qt5/%.hxx \ diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk index 0be72cb7d6f1..1b094fda79f9 100644 --- a/vcl/Library_vclplug_qt5.mk +++ b/vcl/Library_vclplug_qt5.mk @@ -74,37 +74,37 @@ $(eval $(call gb_Library_add_libs,vclplug_qt5,\ endif $(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\ - vcl/qt5/Qt5AccessibleEventListener \ - vcl/qt5/Qt5AccessibleWidget \ - vcl/qt5/Qt5Bitmap \ - vcl/qt5/Qt5Clipboard \ - vcl/qt5/Qt5Data \ - vcl/qt5/Qt5DragAndDrop \ - vcl/qt5/Qt5FilePicker \ - vcl/qt5/Qt5Font \ - vcl/qt5/Qt5FontFace \ - vcl/qt5/Qt5Frame \ - vcl/qt5/Qt5Graphics \ - vcl/qt5/Qt5Graphics_Controls \ - vcl/qt5/Qt5Graphics_GDI \ - vcl/qt5/Qt5Graphics_Text \ - vcl/qt5/Qt5Instance \ - vcl/qt5/Qt5Instance_Print \ - vcl/qt5/Qt5MainWindow \ - vcl/qt5/Qt5Menu \ - vcl/qt5/Qt5Object \ - vcl/qt5/Qt5OpenGLContext \ - vcl/qt5/Qt5Painter \ - vcl/qt5/Qt5Printer \ - vcl/qt5/Qt5SvpGraphics \ - vcl/qt5/Qt5SvpSurface \ - vcl/qt5/Qt5System \ - vcl/qt5/Qt5Timer \ - vcl/qt5/Qt5Tools \ - vcl/qt5/Qt5Transferable \ - vcl/qt5/Qt5VirtualDevice \ - vcl/qt5/Qt5Widget \ - vcl/qt5/Qt5XAccessible \ + vcl/qt5/QtAccessibleEventListener \ + vcl/qt5/QtAccessibleWidget \ + vcl/qt5/QtBitmap \ + vcl/qt5/QtClipboard \ + vcl/qt5/QtData \ + vcl/qt5/QtDragAndDrop \ + vcl/qt5/QtFilePicker \ + vcl/qt5/QtFont \ + vcl/qt5/QtFontFace \ + vcl/qt5/QtFrame \ + vcl/qt5/QtGraphics \ + vcl/qt5/QtGraphics_Controls \ + vcl/qt5/QtGraphics_GDI \ + vcl/qt5/QtGraphics_Text \ + vcl/qt5/QtInstance \ + vcl/qt5/QtInstance_Print \ + vcl/qt5/QtMainWindow \ + vcl/qt5/QtMenu \ + vcl/qt5/QtObject \ + vcl/qt5/QtOpenGLContext \ + vcl/qt5/QtPainter \ + vcl/qt5/QtPrinter \ + vcl/qt5/QtSvpGraphics \ + vcl/qt5/QtSvpSurface \ + vcl/qt5/QtSystem \ + vcl/qt5/QtTimer \ + vcl/qt5/QtTools \ + vcl/qt5/QtTransferable \ + vcl/qt5/QtVirtualDevice \ + vcl/qt5/QtWidget \ + vcl/qt5/QtXAccessible \ )) ifeq ($(OS),LINUX) diff --git a/vcl/inc/qt5/Qt5AccessibleEventListener.hxx b/vcl/inc/qt5/Qt5AccessibleEventListener.hxx deleted file mode 100644 index 5c66d816fc2a..000000000000 --- a/vcl/inc/qt5/Qt5AccessibleEventListener.hxx +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#pragma once - -#include <com/sun/star/accessibility/XAccessible.hpp> -#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> -#include <com/sun/star/lang/EventObject.hpp> - -#include "Qt5AccessibleWidget.hxx" - -#include <cppuhelper/implbase.hxx> - -class QtAccessibleEventListener final - : public cppu::WeakImplHelper<css::accessibility::XAccessibleEventListener> -{ -public: - QtAccessibleEventListener( - const css::uno::Reference<css::accessibility::XAccessible> xAccessible, - QtAccessibleWidget* pAccessibleWidget); - - virtual void SAL_CALL - notifyEvent(const css::accessibility::AccessibleEventObject& aEvent) override; - - virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; - -private: - css::uno::Reference<css::accessibility::XAccessible> m_xAccessible; - QtAccessibleWidget* m_pAccessibleWidget; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5AccessibleWidget.hxx b/vcl/inc/qt5/Qt5AccessibleWidget.hxx deleted file mode 100644 index 102b5658fb28..000000000000 --- a/vcl/inc/qt5/Qt5AccessibleWidget.hxx +++ /dev/null @@ -1,159 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <vclpluginapi.h> - -#include <QtCore/QObject> -#include <QtCore/QPair> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVector> -#include <QtGui/QAccessible> -#include <QtGui/QAccessibleActionInterface> -#include <QtGui/QAccessibleInterface> -#include <QtGui/QAccessibleTableCellInterface> -#include <QtGui/QAccessibleTableInterface> -#include <QtGui/QAccessibleTextInterface> -#include <QtGui/QAccessibleValueInterface> -#include <QtGui/QColor> -#include <QtGui/QWindow> - -#include <com/sun/star/accessibility/XAccessible.hpp> - -namespace com::sun::star::accessibility -{ -class XAccessibleTable; -} - -class QtFrame; -class QtWidget; - -class QtAccessibleWidget final : public QObject, - public QAccessibleInterface, - public QAccessibleActionInterface, - public QAccessibleTextInterface, - public QAccessibleEditableTextInterface, - public QAccessibleTableCellInterface, - public QAccessibleTableInterface, - public QAccessibleValueInterface -{ - Q_OBJECT - -public: - QtAccessibleWidget(const css::uno::Reference<css::accessibility::XAccessible> xAccessible, - QObject* pObject); - QWindow* window() const override; - int childCount() const override; - int indexOfChild(const QAccessibleInterface* child) const override; - QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> - relations(QAccessible::Relation match = QAccessible::AllRelations) const override; - QAccessibleInterface* focusChild() const override; - - QRect rect() const override; - - QAccessibleInterface* parent() const override; - QAccessibleInterface* child(int index) const override; - - QString text(QAccessible::Text t) const override; - QAccessible::Role role() const override; - QAccessible::State state() const override; - - QColor foregroundColor() const override; - QColor backgroundColor() const override; - - bool isValid() const override; - QObject* object() const override; - void setText(QAccessible::Text t, const QString& text) override; - QAccessibleInterface* childAt(int x, int y) const override; - - void* interface_cast(QAccessible::InterfaceType t) override; - - // QAccessibleActionInterface - QStringList actionNames() const override; - void doAction(const QString& actionName) override; - QStringList keyBindingsForAction(const QString& actionName) const override; - - // QAccessibleTextInterface - void addSelection(int startOffset, int endOffset) override; - QString attributes(int offset, int* startOffset, int* endOffset) const override; - int characterCount() const override; - QRect characterRect(int offset) const override; - int cursorPosition() const override; - int offsetAtPoint(const QPoint& point) const override; - void removeSelection(int selectionIndex) override; - void scrollToSubstring(int startIndex, int endIndex) override; - void selection(int selectionIndex, int* startOffset, int* endOffset) const override; - int selectionCount() const override; - void setCursorPosition(int position) override; - void setSelection(int selectionIndex, int startOffset, int endOffset) override; - QString text(int startOffset, int endOffset) const override; - QString textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int* startOffset, int* endOffset) const override; - QString textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int* startOffset, - int* endOffset) const override; - QString textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int* startOffset, int* endOffset) const override; - - // QAccessibleEditableTextInterface - virtual void deleteText(int startOffset, int endOffset) override; - virtual void insertText(int offset, const QString& text) override; - virtual void replaceText(int startOffset, int endOffset, const QString& text) override; - - // QAccessibleValueInterface - QVariant currentValue() const override; - QVariant maximumValue() const override; - QVariant minimumStepSize() const override; - QVariant minimumValue() const override; - void setCurrentValue(const QVariant& value) override; - - // QAccessibleTableInterface - virtual QAccessibleInterface* caption() const override; - virtual QAccessibleInterface* cellAt(int row, int column) const override; - virtual int columnCount() const override; - virtual QString columnDescription(int column) const override; - virtual bool isColumnSelected(int column) const override; - virtual bool isRowSelected(int row) const override; - virtual void modelChange(QAccessibleTableModelChangeEvent* event) override; - virtual int rowCount() const override; - virtual QString rowDescription(int row) const override; - virtual bool selectColumn(int column) override; - virtual bool selectRow(int row) override; - virtual int selectedCellCount() const override; - virtual QList<QAccessibleInterface*> selectedCells() const override; - virtual int selectedColumnCount() const override; - virtual QList<int> selectedColumns() const override; - virtual int selectedRowCount() const override; - virtual QList<int> selectedRows() const override; - virtual QAccessibleInterface* summary() const override; - virtual bool unselectColumn(int column) override; - virtual bool unselectRow(int row) override; - - // QAccessibleTableCellInterface - virtual QList<QAccessibleInterface*> columnHeaderCells() const override; - virtual int columnIndex() const override; - virtual bool isSelected() const override; - virtual int columnExtent() const override; - virtual QList<QAccessibleInterface*> rowHeaderCells() const override; - virtual int rowExtent() const override; - virtual int rowIndex() const override; - virtual QAccessibleInterface* table() const override; - - // Factory - static QAccessibleInterface* customFactory(const QString& classname, QObject* object); - -private: - css::uno::Reference<css::accessibility::XAccessible> m_xAccessible; - css::uno::Reference<css::accessibility::XAccessibleContext> getAccessibleContextImpl() const; - css::uno::Reference<css::accessibility::XAccessibleTable> getAccessibleTableForParent() const; - QObject* m_pObject; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Bitmap.hxx b/vcl/inc/qt5/Qt5Bitmap.hxx deleted file mode 100644 index a15deab29460..000000000000 --- a/vcl/inc/qt5/Qt5Bitmap.hxx +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <salbmp.hxx> - -#include <memory> - -class QImage; - -class QtBitmap final : public SalBitmap -{ - std::unique_ptr<QImage> m_pImage; - BitmapPalette m_aPalette; - -public: - QtBitmap(); - QtBitmap(const QImage& rQImage); - - const QImage* GetQImage() const { return m_pImage.get(); } - - virtual bool Create(const Size& rSize, vcl::PixelFormat ePixelFormat, - const BitmapPalette& rPal) override; - virtual bool Create(const SalBitmap& rSalBmp) override; - virtual bool Create(const SalBitmap& rSalBmp, SalGraphics* pGraphics) override; - virtual bool Create(const SalBitmap& rSalBmp, vcl::PixelFormat eNewPixelFormat) override; - virtual bool Create(const css::uno::Reference<css::rendering::XBitmapCanvas>& rBitmapCanvas, - Size& rSize, bool bMask = false) override; - virtual void Destroy() final override; - virtual Size GetSize() const override; - virtual sal_uInt16 GetBitCount() const override; - - virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override; - virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) override; - virtual bool GetSystemData(BitmapSystemData& rData) override; - - virtual bool ScalingSupported() const override; - virtual bool Scale(const double& rScaleX, const double& rScaleY, - BmpScaleFlag nScaleFlag) override; - virtual bool Replace(const Color& rSearchColor, const Color& rReplaceColor, - sal_uInt8 nTol) override; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Clipboard.hxx b/vcl/inc/qt5/Qt5Clipboard.hxx deleted file mode 100644 index 69c2f7a27d9e..000000000000 --- a/vcl/inc/qt5/Qt5Clipboard.hxx +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - */ - -#pragma once - -#include <com/sun/star/lang/XServiceInfo.hpp> -#include <com/sun/star/datatransfer/XTransferable.hpp> -#include <com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp> -#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> -#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp> -#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp> -#include <cppuhelper/compbase.hxx> - -#include <QtGui/QClipboard> - -/** - * This implementation has two main functions, which handle the clipboard content: - * the XClipboard::setContent function and the QClipboard::change signal handler. - * - * The first just sets the respective clipboard to the expected content from LO, - * the latter will handle any reported changes. - **/ -class QtClipboard final - : public QObject, - public cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard, - css::datatransfer::clipboard::XFlushableClipboard, - css::lang::XServiceInfo> -{ - Q_OBJECT - - osl::Mutex m_aMutex; - const OUString m_aClipboardName; - const QClipboard::Mode m_aClipboardMode; - // has to be set, if LO changes the QClipboard itself, so it won't instantly lose - // ownership by it's self-triggered QClipboard::changed handler - bool m_bOwnClipboardChange; - // true, if LO really wants to give up clipboard ownership - bool m_bDoClear; - - // if not empty, this holds the setContents provided XTransferable or a QtClipboardTransferable - css::uno::Reference<css::datatransfer::XTransferable> m_aContents; - // the owner of the current contents, which must be informed on content change - css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner; - std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> m_aListeners; - - static bool isOwner(const QClipboard::Mode aMode); - static bool isSupported(const QClipboard::Mode aMode); - - explicit QtClipboard(const OUString& aModeString, const QClipboard::Mode aMode); - -private Q_SLOTS: - void handleChanged(QClipboard::Mode mode); - void handleClearClipboard(); - -signals: - void clearClipboard(); - -public: - // factory function to construct only valid QtClipboard objects by name - static css::uno::Reference<css::uno::XInterface> create(const OUString& aModeString); - - // 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; - - // XClipboard - virtual css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override; - virtual void SAL_CALL setContents( - const css::uno::Reference<css::datatransfer::XTransferable>& xTrans, - const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner) - override; - virtual OUString SAL_CALL getName() override; - - // XClipboardEx - virtual sal_Int8 SAL_CALL getRenderingCapabilities() override; - - // XFlushableClipboard - virtual void SAL_CALL flushClipboard() override; - - // XClipboardNotifier - virtual void SAL_CALL addClipboardListener( - const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) - override; - virtual void SAL_CALL removeClipboardListener( - const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) - override; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Data.hxx b/vcl/inc/qt5/Qt5Data.hxx deleted file mode 100644 index ef8ee8f6f8f1..000000000000 --- a/vcl/inc/qt5/Qt5Data.hxx +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <unx/gendata.hxx> - -#include <o3tl/enumarray.hxx> -#include <vcl/ptrstyle.hxx> -#include <memory> -#include <vclpluginapi.h> - -class QCursor; - -class VCLPLUG_QT5_PUBLIC QtData final : public GenericUnixSalData -{ - o3tl::enumarray<PointerStyle, std::unique_ptr<QCursor>> m_aCursors; - -public: - explicit QtData(SalInstance* pInstance); - virtual ~QtData() override; - - virtual void ErrorTrapPush() override; - virtual bool ErrorTrapPop(bool bIgnoreError = true) override; - - QCursor& getCursor(PointerStyle ePointerStyle); - - static bool noNativeControls(); -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5DragAndDrop.hxx b/vcl/inc/qt5/Qt5DragAndDrop.hxx deleted file mode 100644 index 0ca1ebfb83aa..000000000000 --- a/vcl/inc/qt5/Qt5DragAndDrop.hxx +++ /dev/null @@ -1,115 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - */ - -#pragma once - -#include <com/sun/star/datatransfer/dnd/XDragSource.hpp> -#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> -#include <com/sun/star/lang/XInitialization.hpp> -#include <com/sun/star/lang/XServiceInfo.hpp> -#include <cppuhelper/compbase.hxx> - -class QtFrame; - -class QtDragSource final - : public cppu::WeakComponentImplHelper<css::datatransfer::dnd::XDragSource, - css::lang::XInitialization, css::lang::XServiceInfo> -{ - osl::Mutex m_aMutex; - QtFrame* m_pFrame; - css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> m_xListener; - -public: - QtDragSource() - : WeakComponentImplHelper(m_aMutex) - , m_pFrame(nullptr) - { - } - - virtual ~QtDragSource() override; - - // XDragSource - virtual sal_Bool SAL_CALL isDragImageSupported() override; - virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction) override; - virtual void SAL_CALL startDrag( - const css::datatransfer::dnd::DragGestureEvent& trigger, sal_Int8 sourceActions, - sal_Int32 cursor, sal_Int32 image, - const css::uno::Reference<css::datatransfer::XTransferable>& transferable, - const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& listener) override; - - // XInitialization - virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override; - void deinitialize(); - - OUString SAL_CALL getImplementationName() override; - - sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; - - css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; - - void fire_dragEnd(sal_Int8 nAction, bool bSuccessful); -}; - -class QtDropTarget final - : public cppu::WeakComponentImplHelper<css::datatransfer::dnd::XDropTarget, - css::datatransfer::dnd::XDropTargetDragContext, - css::datatransfer::dnd::XDropTargetDropContext, - css::lang::XInitialization, css::lang::XServiceInfo> -{ - osl::Mutex m_aMutex; - QtFrame* m_pFrame; - sal_Int8 m_nDropAction; - bool m_bActive; - sal_Int8 m_nDefaultActions; - std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> m_aListeners; - bool m_bDropSuccessful; - -public: - QtDropTarget(); - virtual ~QtDropTarget() override; - - // XInitialization - virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArgs) override; - void deinitialize(); - - // XDropTarget - virtual void SAL_CALL addDropTargetListener( - const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>&) override; - virtual void SAL_CALL removeDropTargetListener( - const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>&) override; - virtual sal_Bool SAL_CALL isActive() override; - virtual void SAL_CALL setActive(sal_Bool active) override; - virtual sal_Int8 SAL_CALL getDefaultActions() override; - virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override; - - // XDropTargetDragContext - virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) override; - virtual void SAL_CALL rejectDrag() override; - - // XDropTargetDropContext - virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) override; - virtual void SAL_CALL rejectDrop() override; - virtual void SAL_CALL dropComplete(sal_Bool success) override; - - // XServiceInfo - OUString SAL_CALL getImplementationName() override; - sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; - css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; - - void fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde); - void fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte); - void fire_dragOver(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde); - void fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde); - - sal_Int8 proposedDropAction() const { return m_nDropAction; } - bool dropSuccessful() const { return m_bDropSuccessful; } -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5FilePicker.hxx b/vcl/inc/qt5/Qt5FilePicker.hxx deleted file mode 100644 index ffad1acc6f2f..000000000000 --- a/vcl/inc/qt5/Qt5FilePicker.hxx +++ /dev/null @@ -1,176 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <vclpluginapi.h> - -#include <cppuhelper/compbase.hxx> - -#include <com/sun/star/frame/XTerminateListener.hpp> -#include <com/sun/star/lang/XInitialization.hpp> -#include <com/sun/star/lang/XServiceInfo.hpp> -#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> -#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> -#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> -#include <com/sun/star/uno/XComponentContext.hpp> - -#include <osl/conditn.hxx> -#include <osl/mutex.hxx> -#include <unotools/resmgr.hxx> - -#include <QtCore/QObject> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QHash> -#include <QtWidgets/QFileDialog> - -#include <memory> - -class QComboBox; -class QGridLayout; -class QLabel; -class QWidget; - -typedef ::cppu::WeakComponentImplHelper<css::frame::XTerminateListener, css::lang::XInitialization, - css::lang::XServiceInfo, css::ui::dialogs::XFilePicker3, - css::ui::dialogs::XFilePickerControlAccess, - css::ui::dialogs::XFolderPicker2> - QtFilePicker_Base; - -class VCLPLUG_QT5_PUBLIC QtFilePicker : public QObject, public QtFilePicker_Base -{ - Q_OBJECT - -private: - css::uno::Reference<css::uno::XComponentContext> m_context; - - css::uno::Reference<css::ui::dialogs::XFilePickerListener> m_xListener; - - osl::Mutex m_aHelperMutex; ///< mutex used by the WeakComponentImplHelper - - QStringList m_aNamedFilterList; ///< to keep the original sequence - QHash<QString, QString> m_aTitleToFilterMap; - // to retrieve the filename extension for a given filter - QHash<QString, QString> m_aNamedFilterToExtensionMap; - QString m_aCurrentFilter; - - QGridLayout* m_pLayout; ///< layout for extra custom controls - QHash<sal_Int16, QWidget*> m_aCustomWidgetsMap; ///< map of SAL control ID's to widget - - const bool m_bIsFolderPicker; - - QWidget* m_pParentWidget; - -protected: - std::unique_ptr<QFileDialog> m_pFileDialog; ///< the file picker dialog - QWidget* m_pExtraControls; ///< widget to contain extra custom controls - -public: - // use non-native file dialog by default; there's no easy way to add custom widgets - // in a generic way in the native one - explicit QtFilePicker(css::uno::Reference<css::uno::XComponentContext> const& context, - QFileDialog::FileMode, bool bUseNative = false); - virtual ~QtFilePicker() override; - - // XFilePickerNotifier - virtual void SAL_CALL addFilePickerListener( - const css::uno::Reference<css::ui::dialogs::XFilePickerListener>& xListener) override; - virtual void SAL_CALL removeFilePickerListener( - const css::uno::Reference<css::ui::dialogs::XFilePickerListener>& xListener) override; - - // XFilterManager functions - virtual void SAL_CALL appendFilter(const OUString& rTitle, const OUString& rFilter) override; - virtual void SAL_CALL setCurrentFilter(const OUString& rTitle) override; - virtual OUString SAL_CALL getCurrentFilter() override; - - // XFilterGroupManager functions - virtual void SAL_CALL - appendFilterGroup(const OUString& rGroupTitle, - const css::uno::Sequence<css::beans::StringPair>& rFilters) override; - - // XCancellable - virtual void SAL_CALL cancel() override; - - // XExecutableDialog functions - virtual void SAL_CALL setTitle(const OUString& rTitle) override; - virtual sal_Int16 SAL_CALL execute() override; - - // XFilePicker functions - virtual void SAL_CALL setMultiSelectionMode(sal_Bool bMode) override; - virtual void SAL_CALL setDefaultName(const OUString& rName) override; - virtual void SAL_CALL setDisplayDirectory(const OUString& rDirectory) override; - virtual OUString SAL_CALL getDisplayDirectory() override; - virtual css::uno::Sequence<OUString> SAL_CALL getFiles() override; - - // XFilePickerControlAccess functions - virtual void SAL_CALL setValue(sal_Int16 nControlId, sal_Int16 nControlAction, - const css::uno::Any& rValue) override; - virtual css::uno::Any SAL_CALL getValue(sal_Int16 nControlId, - sal_Int16 nControlAction) override; - virtual void SAL_CALL enableControl(sal_Int16 nControlId, sal_Bool bEnable) override; - virtual void SAL_CALL setLabel(sal_Int16 nControlId, const OUString& rLabel) override; - virtual OUString SAL_CALL getLabel(sal_Int16 nControlId) override; - - // XFilePicker2 functions - virtual css::uno::Sequence<OUString> SAL_CALL getSelectedFiles() override; - - // XInitialization - virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override; - - // XEventListener - void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; - using cppu::WeakComponentImplHelperBase::disposing; - - // 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; - - // XFolderPicker functions - virtual OUString SAL_CALL getDirectory() override; - virtual void SAL_CALL setDescription(const OUString& rDescription) override; - - // XTerminateListener - void SAL_CALL queryTermination(const css::lang::EventObject& aEvent) override; - void SAL_CALL notifyTermination(const css::lang::EventObject& aEvent) override; - -protected: - virtual void addCustomControl(sal_Int16 controlId); - void setCustomControlWidgetLayout(QGridLayout* pLayout) { m_pLayout = pLayout; } - -private: - QtFilePicker(const QtFilePicker&) = delete; - QtFilePicker& operator=(const QtFilePicker&) = delete; - - static QString getResString(TranslateId pRedId); - static css::uno::Any handleGetListValue(const QComboBox* pWidget, sal_Int16 nControlAction); - static void handleSetListValue(QComboBox* pQComboBox, sal_Int16 nAction, - const css::uno::Any& rValue); - -private Q_SLOTS: - // emit XFilePickerListener controlStateChanged event - void filterSelected(const QString&); - // emit XFilePickerListener fileSelectionChanged event - void currentChanged(const QString&); - // (un)set automatic file extension - virtual void updateAutomaticFileExtension(); -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Font.hxx b/vcl/inc/qt5/Qt5Font.hxx deleted file mode 100644 index 8c9d83c595c0..000000000000 --- a/vcl/inc/qt5/Qt5Font.hxx +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in 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 <fontinstance.hxx> - -#include <QtGui/QFont> - -#include "Qt5FontFace.hxx" - -class QtFont final : public QFont, public LogicalFontInstance -{ - friend rtl::Reference<LogicalFontInstance> - QtFontFace::CreateFontInstance(const vcl::font::FontSelectPattern&) const; - - bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override; - bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; - - virtual hb_font_t* ImplInitHbFont() override; - - explicit QtFont(const PhysicalFontFace&, const vcl::font::FontSelectPattern&); -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5FontFace.hxx b/vcl/inc/qt5/Qt5FontFace.hxx deleted file mode 100644 index 2f15a26e308b..000000000000 --- a/vcl/inc/qt5/Qt5FontFace.hxx +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in 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 <vclpluginapi.h> -#include <PhysicalFontFace.hxx> - -#include <tools/ref.hxx> -#include <vcl/fontcapabilities.hxx> -#include <vcl/fontcharmap.hxx> - -#include <QtCore/QString> -#include <QtGui/QFont> - -class FontAttributes; -namespace vcl::font -{ -class FontSelectPattern; -} - -class QtFontFace final : public PhysicalFontFace -{ -public: - static QtFontFace* fromQFont(const QFont& rFont); - static QtFontFace* fromQFontDatabase(const QString& aFamily, const QString& aStyle); - static void fillAttributesFromQFont(const QFont& rFont, FontAttributes& rFA); - - VCLPLUG_QT5_PUBLIC static FontWeight toFontWeight(const int nWeight); - VCLPLUG_QT5_PUBLIC static FontWidth toFontWidth(const int nStretch); - VCLPLUG_QT5_PUBLIC static FontItalic toFontItalic(const QFont::Style eStyle); - - sal_IntPtr GetFontId() const override; - - QFont CreateFont() const; - int GetFontTable(const char pTagName[5], unsigned char*) const; - - FontCharMapRef GetFontCharMap() const override; - bool GetFontCapabilities(vcl::FontCapabilities&) const override; - bool HasChar(sal_uInt32 cChar) const; - - rtl::Reference<LogicalFontInstance> - CreateFontInstance(const vcl::font::FontSelectPattern& rFSD) const override; - -private: - typedef enum { Font, FontDB } FontIdType; - - QtFontFace(const QtFontFace&); - QtFontFace(const FontAttributes&, const QString& rFontID, const FontIdType); - - const QString m_aFontId; - const FontIdType m_eFontIdType; - mutable FontCharMapRef m_xCharMap; - mutable vcl::FontCapabilities m_aFontCapabilities; - mutable bool m_bFontCapabilitiesRead; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Frame.hxx b/vcl/inc/qt5/Qt5Frame.hxx deleted file mode 100644 index 3529c0d67c17..000000000000 --- a/vcl/inc/qt5/Qt5Frame.hxx +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <config_vclplug.h> - -#include <salframe.hxx> -#include <vclpluginapi.h> - -#include "Qt5Tools.hxx" - -#include <headless/svpgdi.hxx> -#include <vcl/svapp.hxx> -#include <vcl/sysdata.hxx> - -#include <QtCore/QObject> - -#if QT5_USING_X11 -#include <unx/screensaverinhibitor.hxx> -// any better way to get rid of the X11 / Qt type clashes? -#undef Bool -#undef CursorShape -#undef Expose -#undef KeyPress -#undef KeyRelease -#undef FocusIn -#undef FocusOut -#undef FontChange -#undef None -#undef Status -#undef Unsorted -#endif - -class QtDragSource; -class QtDropTarget; -class QtGraphics; -class QtInstance; -class QtMainWindow; -class QtMenu; -class QtSvpGraphics; - -class QDragMoveEvent; -class QDropEvent; -class QImage; -class QMimeData; -class QPaintDevice; -class QScreen; -class QWidget; - -class VCLPLUG_QT5_PUBLIC QtFrame : public QObject, public SalFrame -{ - Q_OBJECT - - friend class QtWidget; - - QWidget* m_pQWidget; - QtMainWindow* m_pTopLevel; - - const bool m_bUseCairo; - std::unique_ptr<QImage> m_pQImage; - std::unique_ptr<QtGraphics> m_pQtGraphics; - UniqueCairoSurface m_pSurface; - std::unique_ptr<QtSvpGraphics> m_pSvpGraphics; - DamageHandler m_aDamageHandler; - QRegion m_aRegion; - bool m_bNullRegion; - - bool m_bGraphicsInUse; - SalFrameStyleFlags m_nStyle; - QtFrame* m_pParent; - PointerStyle m_ePointerStyle; - - SystemEnvData m_aSystemData; - - QtDragSource* m_pDragSource; - QtDropTarget* m_pDropTarget; - bool m_bInDrag; - - bool m_bDefaultSize; - bool m_bDefaultPos; - bool m_bFullScreen; - bool m_bFullScreenSpanAll; - sal_uInt32 m_nRestoreScreen; - QRect m_aRestoreGeometry; - -#if QT5_USING_X11 - ScreenSaverInhibitor m_ScreenSaverInhibitor; - ModKeyFlags m_nKeyModifiers; -#endif - - LanguageType m_nInputLanguage; - - void SetDefaultPos(); - Size CalcDefaultSize(); - void SetDefaultSize(); - - bool isChild(bool bPlug = true, bool bSysChild = true) const - { - SalFrameStyleFlags nMask = SalFrameStyleFlags::NONE; - if (bPlug) - nMask |= SalFrameStyleFlags::PLUG; - if (bSysChild) - nMask |= SalFrameStyleFlags::SYSTEMCHILD; - return bool(m_nStyle & nMask); - } - - bool isWindow() const; - QWindow* windowHandle() const; - QScreen* screen() const; - bool isMinimized() const; - bool isMaximized() const; - void SetWindowStateImpl(Qt::WindowStates eState); - - void fixICCCMwindowGroup(); - -public: - QtFrame(QtFrame* pParent, SalFrameStyleFlags nSalFrameStyle, bool bUseCairo); - virtual ~QtFrame() override; - - QWidget* GetQWidget() const { return m_pQWidget; } - QtMainWindow* GetTopLevelWindow() const { return m_pTopLevel; } - QWidget* asChild() const; - qreal devicePixelRatioF() const; - - void Damage(sal_Int32 nExtentsX, sal_Int32 nExtentsY, sal_Int32 nExtentsWidth, - sal_Int32 nExtentsHeight) const; - - virtual SalGraphics* AcquireGraphics() override; - virtual void ReleaseGraphics(SalGraphics* pGraphics) override; - - virtual bool PostEvent(std::unique_ptr<ImplSVEvent> pData) override; - - virtual void SetTitle(const OUString& rTitle) override; - virtual void SetIcon(sal_uInt16 nIcon) override; - virtual void SetMenu(SalMenu* pMenu) override; - virtual void DrawMenuBar() override; - - virtual void registerDragSource(QtDragSource* pDragSource); - virtual void deregisterDragSource(QtDragSource const* pDragSource); - virtual void registerDropTarget(QtDropTarget* pDropTarget); - virtual void deregisterDropTarget(QtDropTarget const* pDropTarget); - - void handleDragLeave(); - void handleDragMove(QDragMoveEvent* pEvent); - void handleDrop(QDropEvent* pEvent); - - virtual void SetExtendedFrameStyle(SalExtStyle nExtStyle) override; - virtual void Show(bool bVisible, bool bNoActivate = false) override; - virtual void SetMinClientSize(tools::Long nWidth, tools::Long nHeight) override; - virtual void SetMaxClientSize(tools::Long nWidth, tools::Long nHeight) override; - virtual void SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, - sal_uInt16 nFlags) override; - virtual void GetClientSize(tools::Long& rWidth, tools::Long& rHeight) override; - virtual void GetWorkArea(tools::Rectangle& rRect) override; - virtual SalFrame* GetParent() const override; - virtual void SetModal(bool bModal) override; - virtual bool GetModal() const override; - virtual void SetWindowState(const SalFrameState* pState) override; - virtual bool GetWindowState(SalFrameState* pState) override; - virtual void ShowFullScreen(bool bFullScreen, sal_Int32 nDisplay) override; - virtual void StartPresentation(bool bStart) override; - virtual void SetAlwaysOnTop(bool bOnTop) override; - virtual void ToTop(SalFrameToTop nFlags) override; - virtual void SetPointer(PointerStyle ePointerStyle) override; - virtual void CaptureMouse(bool bMouse) override; - virtual void SetPointerPos(tools::Long nX, tools::Long nY) override; - virtual bool ShowTooltip(const OUString& rText, const tools::Rectangle& rHelpArea) override; - using SalFrame::Flush; - virtual void Flush() override; - virtual void SetInputContext(SalInputContext* pContext) override; - virtual void EndExtTextInput(EndExtTextInputFlags nFlags) override; - virtual OUString GetKeyName(sal_uInt16 nKeyCode) override; - virtual bool MapUnicodeToKeyCode(sal_Unicode aUnicode, LanguageType aLangType, - vcl::KeyCode& rKeyCode) override; - virtual LanguageType GetInputLanguage() override; - virtual void UpdateSettings(AllSettings& rSettings) override; - virtual void Beep() override; - virtual const SystemEnvData* GetSystemData() const override { return &m_aSystemData; } - virtual SalPointerState GetPointerState() override; - virtual KeyIndicatorState GetIndicatorState() override; - virtual void SimulateKeyPress(sal_uInt16 nKeyCode) override; - virtual void SetParent(SalFrame* pNewParent) override; - virtual void SetPluginParent(SystemParentData* pNewParent) override; - virtual void ResetClipRegion() override; - virtual void BeginSetClipRegion(sal_uInt32 nRects) override; - virtual void UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; - virtual void EndSetClipRegion() override; - - virtual void SetScreenNumber(unsigned int) override; - virtual void SetApplicationID(const OUString&) override; - - inline bool CallCallback(SalEvent nEvent, const void* pEvent) const; - - void setInputLanguage(LanguageType); - inline bool isPopup() const; -}; - -inline bool QtFrame::CallCallback(SalEvent nEvent, const void* pEvent) const -{ - SolarMutexGuard aGuard; - return SalFrame::CallCallback(nEvent, pEvent); -} - -inline bool QtFrame::isPopup() const -{ - return ((m_nStyle & SalFrameStyleFlags::FLOAT) - && !(m_nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx deleted file mode 100644 index bd459082548e..000000000000 --- a/vcl/inc/qt5/Qt5Graphics.hxx +++ /dev/null @@ -1,247 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in 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 <salgdi.hxx> - -#include <memory> - -#include <QtGui/QPainter> -#include <QtGui/QPainterPath> -#include <QtGui/QRegion> - -#include "Qt5GraphicsBase.hxx" - -class PhysicalFontCollection; -class QImage; -class QPushButton; -class QtFont; -class QtFontFace; -class QtFrame; -class QtPainter; - -class QtGraphicsBackend final : public SalGraphicsImpl, public QtGraphicsBase -{ - friend class QtPainter; - - QtFrame* m_pFrame; - QImage* m_pQImage; - QRegion m_aClipRegion; - QPainterPath m_aClipPath; - Color m_aLineColor; - Color m_aFillColor; - QPainter::CompositionMode m_eCompositionMode; - -public: - QtGraphicsBackend(QtFrame* pFrame, QImage* pQImage); - ~QtGraphicsBackend() override; - - void Init() override {} - - QImage* getQImage() { return m_pQImage; } - - void setQImage(QImage* pQImage) { m_pQImage = pQImage; } - - void freeResources() override {} - - OUString getRenderBackendName() const override { return "qt5"; } - - bool setClipRegion(vcl::Region const& rRegion) override; - void ResetClipRegion() override; - - sal_uInt16 GetBitCount() const override; - - tools::Long GetGraphicsWidth() const override; - - void SetLineColor() override; - void SetLineColor(Color nColor) override; - void SetFillColor() override; - void SetFillColor(Color nColor) override; - void SetXORMode(bool bSet, bool bInvertOnly) override; - void SetROPLineColor(SalROPColor nROPColor) override; - void SetROPFillColor(SalROPColor nROPColor) override; - - void drawPixel(tools::Long nX, tools::Long nY) override; - void drawPixel(tools::Long nX, tools::Long nY, Color nColor) override; - - void drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2) override; - void drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight) override; - void drawPolyLine(sal_uInt32 nPoints, const Point* pPointArray) override; - void drawPolygon(sal_uInt32 nPoints, const Point* pPointArray) override; - void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, - const Point** pPointArray) override; - - bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolyPolygon&, double fTransparency) override; - - bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, - double fTransparency, double fLineWidth, const std::vector<double>* pStroke, - basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, - bool bPixelSnapHairline) override; - - bool drawPolyLineBezier(sal_uInt32 nPoints, const Point* pPointArray, - const PolyFlags* pFlagArray) override; - - bool drawPolygonBezier(sal_uInt32 nPoints, const Point* pPointArray, - const PolyFlags* pFlagArray) override; - - bool drawPolyPolygonBezier(sal_uInt32 nPoly, const sal_uInt32* pPoints, - const Point* const* pPointArray, - const PolyFlags* const* pFlagArray) override; - - void copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY, - tools::Long nSrcWidth, tools::Long nSrcHeight, bool bWindowInvalidate) override; - - void copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) override; - - void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) override; - - void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, - const SalBitmap& rMaskBitmap) override; - - void drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, - Color nMaskColor) override; - - std::shared_ptr<SalBitmap> getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; - - Color getPixel(tools::Long nX, tools::Long nY) override; - - void invert(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, - SalInvert nFlags) override; - - void invert(sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags) override; - - bool drawEPS(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, - void* pPtr, sal_uInt32 nSize) override; - - bool blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap) override; - - bool blendAlphaBitmap(const SalTwoRect&, const SalBitmap& rSrcBitmap, - const SalBitmap& rMaskBitmap, const SalBitmap& rAlphaBitmap) override; - - bool drawAlphaBitmap(const SalTwoRect&, const SalBitmap& rSourceBitmap, - const SalBitmap& rAlphaBitmap) override; - - bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, - const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; - - bool hasFastDrawTransformedBitmap() const override; - - bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, - sal_uInt8 nTransparency) override; - - bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; - bool implDrawGradient(basegfx::B2DPolyPolygon const& rPolyPolygon, - SalGradient const& rGradient) override; - - bool supportsOperation(OutDevSupportType eType) const override; - -private: - void drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage); -}; - -class QtGraphics final : public SalGraphicsAutoDelegateToImpl, public QtGraphicsBase -{ - friend class QtBitmap; - - std::unique_ptr<QtGraphicsBackend> m_pBackend; - - QtFrame* m_pFrame; - - rtl::Reference<QtFont> m_pTextStyle[MAX_FALLBACK]; - Color m_aTextColor; - - QtGraphics(QtFrame* pFrame, QImage* pQImage); - - void drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage); - - void handleDamage(const tools::Rectangle&) override; - -public: - QtGraphics(QtFrame* pFrame) - : QtGraphics(pFrame, nullptr) - { - } - QtGraphics(QImage* pQImage) - : QtGraphics(nullptr, pQImage) - { - } - virtual ~QtGraphics() override; - - QImage* getQImage() { return m_pBackend->getQImage(); } - - void ChangeQImage(QImage* pImage); - - virtual SalGraphicsImpl* GetImpl() const override; - virtual SystemGraphicsData GetGraphicsData() const override; - virtual OUString getRenderBackendName() const override - { - return m_pBackend->getRenderBackendName(); - } - -#if ENABLE_CAIRO_CANVAS - virtual bool SupportsCairo() const override; - virtual cairo::SurfaceSharedPtr - CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; - virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, - int width, int height) const override; - virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, - const BitmapSystemData& rData, - const Size& rSize) const override; - virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, - const basegfx::B2ISize& rSize) const override; -#endif // ENABLE_CAIRO_CANVAS - - // GDI - - virtual void GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) override; - - // Text rendering + font support - - virtual void SetTextColor(Color nColor) override; - virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) override; - virtual void GetFontMetric(ImplFontMetricDataRef&, int nFallbackLevel) override; - virtual FontCharMapRef GetFontCharMap() const override; - virtual bool GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const override; - virtual void GetDevFontList(PhysicalFontCollection*) override; - virtual void ClearDevFontCache() override; - virtual bool AddTempDevFont(PhysicalFontCollection*, const OUString& rFileURL, - const OUString& rFontName) override; - virtual bool CreateFontSubset(const OUString& rToFile, const PhysicalFontFace* pFont, - const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, - sal_Int32* pWidths, int nGlyphs, - FontSubsetInfo& rInfo // out parameter - ) override; - - virtual const void* GetEmbedFontData(const PhysicalFontFace*, tools::Long* pDataLen) override; - virtual void FreeEmbedFontData(const void* pData, tools::Long nDataLen) override; - - virtual void GetGlyphWidths(const PhysicalFontFace*, bool bVertical, - std::vector<sal_Int32>& rWidths, Ucs2UIntMap& rUnicodeEnc) override; - - virtual std::unique_ptr<GenericSalLayout> GetTextLayout(int nFallbackLevel) override; - virtual void DrawTextLayout(const GenericSalLayout&) override; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5GraphicsBase.hxx b/vcl/inc/qt5/Qt5GraphicsBase.hxx deleted file mode 100644 index 73c39fb5ba80..000000000000 --- a/vcl/inc/qt5/Qt5GraphicsBase.hxx +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <QtWidgets/QApplication> - -class QtGraphicsBase -{ - qreal m_fDPR; - -public: - QtGraphicsBase() - : m_fDPR(qApp ? qApp->devicePixelRatio() : 1.0) - { - } - - void setDevicePixelRatioF(qreal fDPR) { m_fDPR = fDPR; } - - qreal devicePixelRatioF() const { return m_fDPR; } -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Graphics_Controls.hxx b/vcl/inc/qt5/Qt5Graphics_Controls.hxx deleted file mode 100644 index 17039f9d6038..000000000000 --- a/vcl/inc/qt5/Qt5Graphics_Controls.hxx +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <vclpluginapi.h> -#include <WidgetDrawInterface.hxx> - -#include <memory> - -#include <QtGui/QImage> -#include <QtGui/QPainter> -#include <QtGui/QRegion> -#include <QtWidgets/QPushButton> -#include <QtWidgets/QStyle> -#include <QtWidgets/QStyleOption> - -class QtGraphicsBase; - -class QtGraphics_Controls final : public vcl::WidgetDrawInterface -{ - std::unique_ptr<QImage> m_image; - QRect m_lastPopupRect; - QtGraphicsBase const& m_rGraphics; - -public: - QtGraphics_Controls(const QtGraphicsBase& rGraphics); - - QImage* getImage() { return m_image.get(); } - - bool isNativeControlSupported(ControlType nType, ControlPart nPart) override; - bool hitTestNativeControl(ControlType nType, ControlPart nPart, - const tools::Rectangle& rControlRegion, const Point& aPos, - bool& rIsInside) override; - bool drawNativeControl(ControlType nType, ControlPart nPart, - const tools::Rectangle& rControlRegion, ControlState nState, - const ImplControlValue& aValue, const OUString& aCaption, - const Color& rBackgroundColor) override; - bool getNativeControlRegion(ControlType nType, ControlPart nPart, - const tools::Rectangle& rControlRegion, ControlState nState, - const ImplControlValue& aValue, const OUString& aCaption, - tools::Rectangle& rNativeBoundingRegion, - tools::Rectangle& rNativeContentRegion) override; - -private: - static int pixelMetric(QStyle::PixelMetric metric, const QStyleOption* option = nullptr); - static QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption* option, - const QSize& contentsSize); - static QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex* option, - QStyle::SubControl subControl); - static QRect subElementRect(QStyle::SubElement element, const QStyleOption* option); - - void draw(QStyle::ControlElement element, QStyleOption& rOption, QImage* image, - const Color& rBackgroundColor, QStyle::State const state = QStyle::State_None, - QRect rect = QRect()); - void draw(QStyle::PrimitiveElement element, QStyleOption& rOption, QImage* image, - const Color& rBackgroundColor, QStyle::State const state = QStyle::State_None, - QRect rect = QRect()); - void draw(QStyle::ComplexControl element, QStyleOptionComplex& rOption, QImage* image, - const Color& rBackgroundColor, QStyle::State const state = QStyle::State_None); - void drawFrame(QStyle::PrimitiveElement element, QImage* image, const Color& rBackGroundColor, - QStyle::State const& state, bool bClip = true, - QStyle::PixelMetric eLineMetric = QStyle::PM_DefaultFrameWidth); - - static void fillQStyleOptionTab(const ImplControlValue& value, QStyleOptionTab& sot); - void fullQStyleOptionTabWidgetFrame(QStyleOptionTabWidgetFrame& option, bool bDownscale); - - enum class Round - { - Floor, - Ceil, - }; - - int downscale(int value, Round eRound); - int upscale(int value, Round eRound); - QRect downscale(const QRect& rect); - QRect upscale(const QRect& rect); - QSize downscale(const QSize& size, Round eRound); - QSize upscale(const QSize& size, Round eRound); - QPoint upscale(const QPoint& point, Round eRound); -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Instance.hxx b/vcl/inc/qt5/Qt5Instance.hxx deleted file mode 100644 index c895e1e0cd00..000000000000 --- a/vcl/inc/qt5/Qt5Instance.hxx +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <vclpluginapi.h> -#include <unx/geninst.h> -#include <salusereventlist.hxx> -#include <vcl/timer.hxx> - -#include <osl/conditn.hxx> - -#include <QtCore/QObject> - -#include <cstdlib> -#include <functional> -#include <memory> -#include <vector> - -#include "Qt5FilePicker.hxx" - -class QtTimer; - -class QApplication; -class SalYieldMutex; -class SalFrame; - -struct StdFreeCStr -{ - void operator()(char* arg) const noexcept { std::free(arg); } -}; -using FreeableCStr = std::unique_ptr<char[], StdFreeCStr>; - -class VCLPLUG_QT5_PUBLIC QtInstance : public QObject, - public SalGenericInstance, - public SalUserEventList -{ - Q_OBJECT - - osl::Condition m_aWaitingYieldCond; - const bool m_bUseCairo; - QtTimer* m_pTimer; - bool m_bSleeping; - std::unordered_map<OUString, css::uno::Reference<css::uno::XInterface>> m_aClipboards; - - std::unique_ptr<QApplication> m_pQApplication; - std::vector<FreeableCStr> m_pFakeArgvFreeable; - std::unique_ptr<char* []> m_pFakeArgv; - std::unique_ptr<int> m_pFakeArgc; - - Timer m_aUpdateStyleTimer; - bool m_bUpdateFonts; - - DECL_LINK(updateStyleHdl, Timer*, void); - void AfterAppInit() override; - -private Q_SLOTS: - bool ImplYield(bool bWait, bool bHandleAllCurrentEvents); - static void deleteObjectLater(QObject* pObject); - static void localeChanged(); - -Q_SIGNALS: - bool ImplYieldSignal(bool bWait, bool bHandleAllCurrentEvents); - void deleteObjectLaterSignal(QObject* pObject); - -protected: - virtual rtl::Reference<QtFilePicker> - createPicker(css::uno::Reference<css::uno::XComponentContext> const& context, - QFileDialog::FileMode); - bool useCairo() const { return m_bUseCairo; } - // encodes cairo usage and Qt platform name into the ToolkitName - OUString constructToolkitID(std::u16string_view sTKname); - -public: - explicit QtInstance(std::unique_ptr<QApplication>& pQApp, bool bUseCairo = false); - virtual ~QtInstance() override; - - // handle common SalInstance setup - static void AllocFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, - std::unique_ptr<int>& rFakeArgc, - std::vector<FreeableCStr>& rFakeArgvFreeable); - void MoveFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, std::unique_ptr<int>& rFakeArgc, - std::vector<FreeableCStr>& rFakeArgvFreeable); - static std::unique_ptr<QApplication> CreateQApplication(int& nArgc, char** pArgv); - - void RunInMainThread(std::function<void()> func); - - virtual SalFrame* CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) override; - virtual SalFrame* CreateChildFrame(SystemParentData* pParent, - SalFrameStyleFlags nStyle) override; - virtual void DestroyFrame(SalFrame* pFrame) override; - - virtual SalObject* CreateObject(SalFrame* pParent, SystemWindowData* pWindowData, - bool bShow) override; - virtual void DestroyObject(SalObject* pObject) override; - - virtual std::unique_ptr<SalVirtualDevice> - CreateVirtualDevice(SalGraphics& rGraphics, tools::Long& nDX, tools::Long& nDY, - DeviceFormat eFormat, const SystemGraphicsData* pData = nullptr) override; - - virtual SalInfoPrinter* CreateInfoPrinter(SalPrinterQueueInfo* pQueueInfo, - ImplJobSetup* pSetupData) override; - virtual void DestroyInfoPrinter(SalInfoPrinter* pPrinter) override; - virtual std::unique_ptr<SalPrinter> CreatePrinter(SalInfoPrinter* pInfoPrinter) override; - virtual void GetPrinterQueueInfo(ImplPrnQueueList* pList) override; - virtual void GetPrinterQueueState(SalPrinterQueueInfo* pInfo) override; - virtual OUString GetDefaultPrinter() override; - virtual void PostPrintersChanged() override; - - virtual std::unique_ptr<SalMenu> CreateMenu(bool, Menu*) override; - virtual std::unique_ptr<SalMenuItem> CreateMenuItem(const SalItemParams&) override; - - virtual SalTimer* CreateSalTimer() override; - virtual SalSystem* CreateSalSystem() override; - virtual std::shared_ptr<SalBitmap> CreateSalBitmap() override; - - virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; - virtual bool AnyInput(VclInputFlags nType) override; - -// so we fall back to the default abort, instead of duplicating it... -#ifndef EMSCRIPTEN - virtual OpenGLContext* CreateOpenGLContext() override; -#endif - - virtual OUString GetConnectionIdentifier() override; - - virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, - const OUString& rDocumentService) override; - - virtual std::unique_ptr<GenPspGraphics> CreatePrintGraphics() override; - - virtual bool IsMainThread() const override; - - virtual void TriggerUserEventProcessing() override; - virtual void ProcessEvent(SalUserEvent aEvent) override; - - bool hasNativeFileSelection() const override { return true; } - css::uno::Reference<css::ui::dialogs::XFilePicker2> - createFilePicker(const css::uno::Reference<css::uno::XComponentContext>&) override; - css::uno::Reference<css::ui::dialogs::XFolderPicker2> - createFolderPicker(const css::uno::Reference<css::uno::XComponentContext>&) override; - - virtual css::uno::Reference<css::uno::XInterface> - CreateClipboard(const css::uno::Sequence<css::uno::Any>& i_rArguments) override; - virtual css::uno::Reference<css::uno::XInterface> CreateDragSource() override; - virtual css::uno::Reference<css::uno::XInterface> CreateDropTarget() override; - - void UpdateStyle(bool bFontsChanged); - - void* CreateGStreamerSink(const SystemChildWindow*) override; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5MainWindow.hxx b/vcl/inc/qt5/Qt5MainWindow.hxx deleted file mode 100644 index ec5c9058636b..000000000000 --- a/vcl/inc/qt5/Qt5MainWindow.hxx +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <QtWidgets/QWidget> -#include <QtWidgets/QMainWindow> - -#include "Qt5Frame.hxx" - -class QtMainWindow final : public QMainWindow -{ - Q_OBJECT - - QtFrame& m_rFrame; - - virtual void closeEvent(QCloseEvent* pEvent) override; - void moveEvent(QMoveEvent*) override; - -public: - QtMainWindow(QtFrame& rFrame, Qt::WindowFlags f = Qt::WindowFlags()); -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Menu.hxx b/vcl/inc/qt5/Qt5Menu.hxx deleted file mode 100644 index 55275ae6e099..000000000000 --- a/vcl/inc/qt5/Qt5Menu.hxx +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <salmenu.hxx> - -#include <QtCore/QObject> - -#include <memory> - -class MenuItemList; -class QAction; -class QActionGroup; -class QPushButton; -class QMenu; -class QMenuBar; -class QtMenuItem; -class QtFrame; - -/* - * QtMenu can represent - * (1) the top-level menu of a menubar, in which case 'mbMenuBar' is true and - * 'mpQMenuBar' refers to the corresponding QMenuBar - * (2) another kind of menu (like a PopupMenu), in which case the corresponding QMenu - * object is instantiated and owned by this QtMenu (held in 'mpOwnedQMenu'). - * (3) a "submenu" in an existing menu (like (1)), in which case the corresponding - * QMenu object is owned by the corresponding QtMenuItem. - * - * For (2) and (3), member 'mpQMenu' points to the corresponding QMenu object. - */ -class QtMenu : public QObject, public SalMenu -{ - Q_OBJECT -private: - std::vector<QtMenuItem*> maItems; - VclPtr<Menu> mpVCLMenu; - QtMenu* mpParentSalMenu; - QtFrame* mpFrame; - bool mbMenuBar; - QMenuBar* mpQMenuBar; - // self-created QMenu that this QtMenu represents, if applicable (s. comment for class) - std::unique_ptr<QMenu> mpOwnedQMenu; - // pointer to QMenu owned by the corresponding QtMenuItem or self (-> mpOwnedQMenu) - QMenu* mpQMenu; - QPushButton* mpCloseButton; - QMetaObject::Connection maCloseButtonConnection; - - void DoFullMenuUpdate(Menu* pMenuBar); - static void NativeItemText(OUString& rItemText); - - void InsertMenuItem(QtMenuItem* pSalMenuItem, unsigned nPos); - - void ReinitializeActionGroup(unsigned nPos); - void ResetAllActionGroups(); - void UpdateActionGroupItem(const QtMenuItem* pSalMenuItem); - -public: - QtMenu(bool bMenuBar); - - virtual bool VisibleMenuBar() override; // must return TRUE to actually DISPLAY native menu bars - - virtual void InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos) override; - virtual void RemoveItem(unsigned nPos) override; - virtual void SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos) override; - virtual void SetFrame(const SalFrame* pFrame) override; - const QtFrame* GetFrame() const; - virtual void ShowMenuBar(bool bVisible) override; - virtual bool ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect, - FloatWinPopupFlags nFlags) override; - QtMenu* GetTopLevel(); - virtual void SetItemBits(unsigned nPos, MenuItemBits nBits) override; - virtual void CheckItem(unsigned nPos, bool bCheck) override; - virtual void EnableItem(unsigned nPos, bool bEnable) override; - virtual void ShowItem(unsigned nPos, bool bShow) override; - virtual void SetItemText(unsigned nPos, SalMenuItem* pSalMenuItem, - const OUString& rText) override; - virtual void SetItemImage(unsigned nPos, SalMenuItem* pSalMenuItem, - const Image& rImage) override; - virtual void SetAccelerator(unsigned nPos, SalMenuItem* pSalMenuItem, - const vcl::KeyCode& rKeyCode, const OUString& rKeyName) override; - virtual void GetSystemMenuData(SystemMenuData* pData) override; - virtual void ShowCloseButton(bool bShow) override; - - void SetMenu(Menu* pMenu) { mpVCLMenu = pMenu; } - Menu* GetMenu() { return mpVCLMenu; } - unsigned GetItemCount() const { return maItems.size(); } - QtMenuItem* GetItemAtPos(unsigned nPos) { return maItems[nPos]; } - -private slots: - static void slotMenuTriggered(QtMenuItem* pQItem); - static void slotMenuAboutToShow(QtMenuItem* pQItem); - static void slotMenuAboutToHide(QtMenuItem* pQItem); - void slotCloseDocument(); -}; - -class QtMenuItem : public SalMenuItem -{ -public: - QtMenuItem(const SalItemParams*); - - QAction* getAction() const; - - QtMenu* mpParentMenu; // The menu into which this menu item is inserted - QtMenu* mpSubMenu; // Submenu of this item (if defined) - std::unique_ptr<QAction> mpAction; // action corresponding to this item - std::unique_ptr<QMenu> mpMenu; // menu corresponding to this item - std::shared_ptr<QActionGroup> mpActionGroup; // empty if it's a separator element - sal_uInt16 mnId; // Item ID - MenuItemType mnType; // Item type - bool mbVisible; // Item visibility. - bool mbEnabled; // Item active. - Image maImage; // Item image -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Object.hxx b/vcl/inc/qt5/Qt5Object.hxx deleted file mode 100644 index 328946e4388e..000000000000 --- a/vcl/inc/qt5/Qt5Object.hxx +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <salobj.hxx> -#include <vcl/sysdata.hxx> - -#include <QtCore/QObject> -#include <QtGui/QRegion> -#include <QtGui/QWindow> - -class QtFrame; -class QWidget; - -class QtObject final : public QObject, public SalObject -{ - Q_OBJECT - - SystemEnvData m_aSystemData; - QtFrame* m_pParent; - QWidget* m_pQWidget; // main widget, container - QWindow* m_pQWindow; // contained window, used for opengl rendering - QRegion m_pRegion; - -public: - QtObject(QtFrame* pParent, bool bShow); - ~QtObject() override; - - QtFrame* frame() const { return m_pParent; } - QWidget* widget() const { return m_pQWidget; } - QWindow* windowHandle() const { return m_pQWindow; } - - virtual void ResetClipRegion() override; - virtual void BeginSetClipRegion(sal_uInt32 nRects) override; - virtual void UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; - virtual void EndSetClipRegion() override; - - virtual void SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; - virtual void Show(bool bVisible) override; - - virtual void SetForwardKey(bool bEnable) override; - - virtual const SystemEnvData* GetSystemData() const override { return &m_aSystemData; } -}; - -class QtObjectWindow final : public QWindow -{ - QtObject& m_rParent; - - bool event(QEvent*) override; - void focusInEvent(QFocusEvent*) override; - void focusOutEvent(QFocusEvent*) override; - void mousePressEvent(QMouseEvent*) override; - void mouseReleaseEvent(QMouseEvent*) override; - // keyPressEvent(QKeyEvent*) is handled via event(QEvent*); see comment in QtWidget::event - void keyReleaseEvent(QKeyEvent*) override; - -public: - explicit QtObjectWindow(QtObject& rParent); -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5OpenGLContext.hxx b/vcl/inc/qt5/Qt5OpenGLContext.hxx deleted file mode 100644 index 8036d50777b9..000000000000 --- a/vcl/inc/qt5/Qt5OpenGLContext.hxx +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in 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/opengl/OpenGLContext.hxx> - -class QWindow; -class QOpenGLContext; - -class QtOpenGLContext final : public OpenGLContext -{ -public: - virtual void initWindow() override; - -private: - virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } - virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } - virtual bool ImplInit() override; - - virtual void makeCurrent() override; - virtual void destroyCurrentContext() override; - virtual bool isCurrent() override; - virtual bool isAnyCurrent() override; - virtual void resetCurrent() override; - virtual void swapBuffers() override; - - static bool g_bAnyCurrent; - - GLWindow m_aGLWin; - - QWindow* m_pWindow; - QOpenGLContext* m_pContext; -}; diff --git a/vcl/inc/qt5/Qt5Painter.hxx b/vcl/inc/qt5/Qt5Painter.hxx deleted file mode 100644 index 803c05ecc071..000000000000 --- a/vcl/inc/qt5/Qt5Painter.hxx +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <QtCore/QRectF> -#include <QtGui/QPainter> -#include <QtWidgets/QWidget> - -#include "Qt5Frame.hxx" -#include "Qt5Graphics.hxx" - -class QtPainter final : public QPainter -{ - QtGraphicsBackend& m_rGraphics; - QRegion m_aRegion; - -public: - QtPainter(QtGraphicsBackend& rGraphics, bool bPrepareBrush = false, - sal_uInt8 nTransparency = 255); - ~QtPainter() - { - if (m_rGraphics.m_pFrame && !m_aRegion.isEmpty()) - m_rGraphics.m_pFrame->GetQWidget()->update(m_aRegion); - } - - void update(int nx, int ny, int nw, int nh) - { - if (m_rGraphics.m_pFrame) - m_aRegion += scaledQRect({ nx, ny, nw, nh }, 1 / m_rGraphics.devicePixelRatioF()); - } - - void update(const QRect& rRect) - { - if (m_rGraphics.m_pFrame) - m_aRegion += scaledQRect(rRect, 1 / m_rGraphics.devicePixelRatioF()); - } - - void update(const QRectF& rRectF) - { - if (m_rGraphics.m_pFrame) - update(scaledQRect(rRectF.toAlignedRect(), 1 / m_rGraphics.devicePixelRatioF())); - } - - void update() - { - if (m_rGraphics.m_pFrame) - m_aRegion += m_rGraphics.m_pFrame->GetQWidget()->rect(); - } -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Printer.hxx b/vcl/inc/qt5/Qt5Printer.hxx deleted file mode 100644 index 5aacfd44ec05..000000000000 --- a/vcl/inc/qt5/Qt5Printer.hxx +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <unx/genprn.h> - -class SalFrame; - -class QtPrinter final : public PspSalPrinter -{ -public: - QtPrinter(SalInfoPrinter* pInfoPrinter); -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5SvpGraphics.hxx b/vcl/inc/qt5/Qt5SvpGraphics.hxx deleted file mode 100644 index ffc164c83373..000000000000 --- a/vcl/inc/qt5/Qt5SvpGraphics.hxx +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <vclpluginapi.h> -#include <headless/svpgdi.hxx> - -#include "Qt5GraphicsBase.hxx" - -class QtFrame; - -class VCLPLUG_QT5_PUBLIC QtSvpGraphics final : public SvpSalGraphics, public QtGraphicsBase -{ - QtFrame* const m_pFrame; - - void handleDamage(const tools::Rectangle&) override; - -public: - QtSvpGraphics(QtFrame* pFrame); - ~QtSvpGraphics() override; - - void updateQWidget() const; - -#if ENABLE_CAIRO_CANVAS - bool SupportsCairo() const override; - cairo::SurfaceSharedPtr - CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; - cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, - int height) const override; -#endif // ENABLE_CAIRO_CANVAS - - virtual void GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) override; - - virtual OUString getRenderBackendName() const override { return "qt5svp"; } -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5SvpSurface.hxx b/vcl/inc/qt5/Qt5SvpSurface.hxx deleted file mode 100644 index 2c2b29cff386..000000000000 --- a/vcl/inc/qt5/Qt5SvpSurface.hxx +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#pragma once - -#include <sal/config.h> - -#include <vcl/cairo.hxx> - -class QtSvpGraphics; -class OutputDevice; - -namespace cairo -{ -class QtSvpSurface final : public Surface -{ - const QtSvpGraphics* m_pGraphics; - cairo_t* const m_pCairoContext; - CairoSurfaceSharedPtr m_pSurface; - -public: - /// takes over ownership of passed cairo_surface - explicit QtSvpSurface(const CairoSurfaceSharedPtr& pSurface); - /// create surface on subarea of given drawable - explicit QtSvpSurface(const QtSvpGraphics* pGraphics, int x, int y, int width, int height); - ~QtSvpSurface() override; - - // Surface interface - CairoSharedPtr getCairo() const override; - CairoSurfaceSharedPtr getCairoSurface() const override { return m_pSurface; } - SurfaceSharedPtr getSimilar(int nContentType, int width, int height) const override; - - VclPtr<VirtualDevice> createVirtualDevice() const override; - void flush() const override; -}; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5System.hxx b/vcl/inc/qt5/Qt5System.hxx deleted file mode 100644 index 6992e381c4c4..000000000000 --- a/vcl/inc/qt5/Qt5System.hxx +++ /dev/null @@ -1,23 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <unx/gensys.h> - -class QtSystem final : public SalGenericSystem -{ -public: - virtual unsigned int GetDisplayScreenCount() override; - virtual tools::Rectangle GetDisplayScreenPosSizePixel(unsigned int nScreen) override; - virtual int ShowNativeDialog(const OUString& rTitle, const OUString& rMessage, - const std::vector<OUString>& rButtons) override; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Timer.hxx b/vcl/inc/qt5/Qt5Timer.hxx deleted file mode 100644 index 204b1bfe43ad..000000000000 --- a/vcl/inc/qt5/Qt5Timer.hxx +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <saltimer.hxx> -#include <QtCore/QTimer> - -class QtTimer final : public QObject, public SalTimer -{ - Q_OBJECT - - QTimer m_aTimer; - -private Q_SLOTS: - void timeoutActivated(); - void startTimer(int); - void stopTimer(); - -Q_SIGNALS: - void startTimerSignal(int); - void stopTimerSignal(); - -public: - QtTimer(); - - int remainingTime() const { return m_aTimer.remainingTime(); } - - virtual void Start(sal_uInt64 nMS) override; - virtual void Stop() override; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Tools.hxx b/vcl/inc/qt5/Qt5Tools.hxx deleted file mode 100644 index 7221a8ce8dc6..000000000000 --- a/vcl/inc/qt5/Qt5Tools.hxx +++ /dev/null @@ -1,182 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <QtCore/QPoint> -#include <QtCore/QRect> -#include <QtCore/QSize> -#include <QtCore/QString> -#include <QtGui/QImage> - -#include <rtl/string.hxx> -#include <rtl/ustring.hxx> -#include <tools/color.hxx> -#include <tools/gen.hxx> -#include <vcl/bitmap/BitmapTypes.hxx> - -#include <com/sun/star/uno/Sequence.hxx> -#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> - -#include <memory> - -class Image; -class QImage; - -inline OUString toOUString(const QString& s) -{ - // QString stores UTF16, just like OUString - return OUString(reinterpret_cast<const sal_Unicode*>(s.data()), s.length()); -} - -inline QString toQString(const OUString& s) -{ - return QString::fromUtf16(s.getStr(), s.getLength()); -} - -inline QRect toQRect(const tools::Rectangle& rRect) -{ - return QRect(rRect.Left(), rRect.Top(), rRect.GetWidth(), rRect.GetHeight()); -} - -inline QRect toQRect(const tools::Rectangle& rRect, const qreal fScale) -{ - return QRect(floor(rRect.Left() * fScale), floor(rRect.Top() * fScale), - ceil(rRect.GetWidth() * fScale), ceil(rRect.GetHeight() * fScale)); -} - -inline QRect scaledQRect(const QRect& rRect, const qreal fScale) -{ - return QRect(floor(rRect.x() * fScale), floor(rRect.y() * fScale), ceil(rRect.width() * fScale), - ceil(rRect.height() * fScale)); -} - -inline tools::Rectangle toRectangle(const QRect& rRect) -{ - return tools::Rectangle(rRect.left(), rRect.top(), rRect.right(), rRect.bottom()); -} - -inline QSize toQSize(const Size& rSize) { return QSize(rSize.Width(), rSize.Height()); } - -inline Size toSize(const QSize& rSize) { return Size(rSize.width(), rSize.height()); } - -inline Point toPoint(const QPoint& rPoint) { return Point(rPoint.x(), rPoint.y()); } - -inline QColor toQColor(const Color& rColor) -{ - return QColor(rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue(), rColor.GetAlpha()); -} - -Qt::DropActions toQtDropActions(sal_Int8 dragOperation); -sal_Int8 toVclDropActions(Qt::DropActions dragOperation); -sal_Int8 toVclDropAction(Qt::DropAction dragOperation); -Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation); - -inline QList<int> toQList(const css::uno::Sequence<sal_Int32>& aSequence) -{ - QList<int> aList; - for (sal_Int32 i : aSequence) - { - aList.append(i); - } - return aList; -} - -constexpr QImage::Format Qt_DefaultFormat32 = QImage::Format_ARGB32; - -inline QImage::Format getBitFormat(vcl::PixelFormat ePixelFormat) -{ - switch (ePixelFormat) - { - case vcl::PixelFormat::N1_BPP: - return QImage::Format_Mono; - case vcl::PixelFormat::N8_BPP: - return QImage::Format_Indexed8; - case vcl::PixelFormat::N24_BPP: - return QImage::Format_RGB888; - case vcl::PixelFormat::N32_BPP: - return Qt_DefaultFormat32; - default: - std::abort(); - break; - } - return QImage::Format_Invalid; -} - -inline sal_uInt16 getFormatBits(QImage::Format eFormat) -{ - switch (eFormat) - { - case QImage::Format_Mono: - return 1; - case QImage::Format_Indexed8: - return 8; - case QImage::Format_RGB888: - return 24; - case Qt_DefaultFormat32: - case QImage::Format_ARGB32_Premultiplied: - return 32; - default: - std::abort(); - return 0; - } -} - -typedef struct _cairo_surface cairo_surface_t; -struct CairoDeleter -{ - void operator()(cairo_surface_t* pSurface) const; -}; - -typedef std::unique_ptr<cairo_surface_t, CairoDeleter> UniqueCairoSurface; - -sal_uInt16 GetKeyModCode(Qt::KeyboardModifiers eKeyModifiers); -sal_uInt16 GetMouseModCode(Qt::MouseButtons eButtons); - -QImage toQImage(const Image& rImage); - -template <typename charT, typename traits> -inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, - const QString& rString) -{ - return stream << toOUString(rString); -} - -template <typename charT, typename traits> -inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, - const QRect& rRect) -{ - return stream << toRectangle(rRect); -} - -template <typename charT, typename traits> -inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, - const QSize& rSize) -{ - return stream << toSize(rSize); -} - -template <typename charT, typename traits> -inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, - const QPoint& rPoint) -{ - return stream << toPoint(rPoint); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Transferable.hxx b/vcl/inc/qt5/Qt5Transferable.hxx deleted file mode 100644 index 8a4410535359..000000000000 --- a/vcl/inc/qt5/Qt5Transferable.hxx +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <cppuhelper/compbase.hxx> -#include <com/sun/star/datatransfer/XTransferable.hpp> - -#include <QtCore/QMimeData> -#include <QtCore/QStringList> -#include <QtGui/QClipboard> - -/** - * QtTransferable classes are used to read QMimeData via the XTransferable - * interface. All the functionality is already implemented in the QtTransferable. - * - * The specialisations map to the two users, which provide QMimeData: the Clipboard - * and the Drag'n'Drop functionality. - * - * LO itself seem to just accept "text/plain;charset=utf-16", so it relies on the - * backend to convert to this charset, but still offers "text/plain" itself. - * - * It's the "mirror" interface of the QtMimeData, which is defined below. - **/ -class QtTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransferable> -{ - QtTransferable(const QtTransferable&) = delete; - - const QMimeData* m_pMimeData; - osl::Mutex m_aMutex; - bool m_bConvertFromLocale; - css::uno::Sequence<css::datatransfer::DataFlavor> m_aMimeTypeSeq; - -public: - QtTransferable(const QMimeData* pMimeData); - const QMimeData* mimeData() const { return m_pMimeData; } - - css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override; - sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; - css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override; -}; - -/** - * The QClipboard's QMimeData is volatile. As written in the QClipboard::mimeData - * documentation, "the pointer returned might become invalidated when the contents - * of the clipboard changes". Therefore it can just be accessed reliably inside - * the QClipboard's object thread, which is the QApplication's thread, so all of - * the access has to go through RunInMainThread(). - * - * If we detect a QMimeData change, we simply drop reporting any content. In theory - * we can recover in the case where there hadn't been any calls of the XTransferable - * interface, but currently we don't. But we ensure to never report mixed content, - * so we'll just cease operation on QMimeData change. - **/ -class QtClipboardTransferable final : public QtTransferable -{ - // to detect in-flight QMimeData changes - const QClipboard::Mode m_aMode; - - bool hasInFlightChanged() const; - -public: - explicit QtClipboardTransferable(const QClipboard::Mode aMode, const QMimeData* pMimeData); - - // these are the same then QtTransferable, except they go through RunInMainThread - css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override; - sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; - css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override; -}; - -/** - * Convenience typedef for better code readability - * - * This just uses the QMimeData provided by the QWidgets D'n'D events. - **/ -typedef QtTransferable QtDnDTransferable; - -/** - * A lazy loading QMimeData for XTransferable reads - * - * This is an interface class to make a XTransferable read accessible as a - * QMimeData. The mime data is just stored inside the XTransferable, never - * in the QMimeData itself! It's objects are just used for QClipboard to read - * the XTransferable data. - * - * Like XTransferable itself, this class should be considered an immutable - * container for mime data. There is no need to ever set any of its data. - * - * LO will offer at least UTF-16, if there is a viable text representation. - * If LO misses to offer a UTF-8 or a locale encoded string, these objects - * will offer them themselves and convert from UTF-16 on demand. - * - * It's the "mirror" interface of the QtTransferable. - **/ -class QtMimeData final : public QMimeData -{ - friend class QtClipboardTransferable; - - const css::uno::Reference<css::datatransfer::XTransferable> m_aContents; - mutable bool m_bHaveNoCharset; // = uses the locale charset - mutable bool m_bHaveUTF8; - mutable QStringList m_aMimeTypeList; - - QVariant retrieveData(const QString& mimeType, QVariant::Type type) const override; - -public: - explicit QtMimeData(const css::uno::Reference<css::datatransfer::XTransferable>& aContents); - - bool hasFormat(const QString& mimeType) const override; - QStringList formats() const override; - - bool deepCopy(QMimeData** const) const; - - css::datatransfer::XTransferable* xTransferable() const { return m_aContents.get(); } -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5VirtualDevice.hxx b/vcl/inc/qt5/Qt5VirtualDevice.hxx deleted file mode 100644 index 2481f63d0657..000000000000 --- a/vcl/inc/qt5/Qt5VirtualDevice.hxx +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <salvd.hxx> - -#include <memory> -#include <vector> - -#include <QtCore/QSize> - -class QtGraphics; -class QImage; -enum class DeviceFormat; - -class QtVirtualDevice final : public SalVirtualDevice -{ - std::vector<QtGraphics*> m_aGraphics; - std::unique_ptr<QImage> m_pImage; - QSize m_aFrameSize; - double m_fScale; - -public: - QtVirtualDevice(double fScale); - - // SalVirtualDevice - virtual SalGraphics* AcquireGraphics() override; - virtual void ReleaseGraphics(SalGraphics* pGraphics) override; - - virtual bool SetSize(tools::Long nNewDX, tools::Long nNewDY) override; - virtual bool SetSizeUsingBuffer(tools::Long nNewDX, tools::Long nNewDY, - sal_uInt8* pBuffer) override; - - // SalGeometryProvider - virtual tools::Long GetWidth() const override; - virtual tools::Long GetHeight() const override; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Widget.hxx b/vcl/inc/qt5/Qt5Widget.hxx deleted file mode 100644 index 801cd290ff88..000000000000 --- a/vcl/inc/qt5/Qt5Widget.hxx +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <QtWidgets/QWidget> -#include <rtl/ustring.hxx> - -#include <com/sun/star/uno/Reference.hxx> -#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> - -class QInputEvent; -class QtFrame; -class QtObject; -struct SalAbstractMouseEvent; - -class QtWidget : public QWidget -{ - Q_OBJECT - - QtFrame& m_rFrame; - bool m_bNonEmptyIMPreeditSeen; - int m_nDeltaX; - int m_nDeltaY; - - enum class ButtonKeyState - { - Pressed, - Released - }; - - static void commitText(QtFrame&, const QString& aText); - static bool handleKeyEvent(QtFrame&, const QWidget&, QKeyEvent*, const ButtonKeyState); - static void handleMouseButtonEvent(const QtFrame&, const QMouseEvent*, const ButtonKeyState); - static void fillSalAbstractMouseEvent(const QtFrame& rFrame, const QInputEvent* pQEvent, - const QPoint& rPos, Qt::MouseButtons eButtons, int nWidth, - SalAbstractMouseEvent& aSalEvent); - - virtual bool event(QEvent*) override; - - virtual void focusInEvent(QFocusEvent*) override; - virtual void focusOutEvent(QFocusEvent*) override; - // keyPressEvent(QKeyEvent*) is handled via event(QEvent*); see comment - virtual void keyReleaseEvent(QKeyEvent*) override; - virtual void mouseMoveEvent(QMouseEvent*) override; - virtual void mousePressEvent(QMouseEvent*) override; - virtual void mouseReleaseEvent(QMouseEvent*) override; - virtual void dragEnterEvent(QDragEnterEvent*) override; - virtual void dragLeaveEvent(QDragLeaveEvent*) override; - virtual void dragMoveEvent(QDragMoveEvent*) override; - virtual void dropEvent(QDropEvent*) override; - virtual void moveEvent(QMoveEvent*) override; - virtual void paintEvent(QPaintEvent*) override; - virtual void resizeEvent(QResizeEvent*) override; - virtual void showEvent(QShowEvent*) override; - virtual void wheelEvent(QWheelEvent*) override; - virtual void closeEvent(QCloseEvent*) override; - virtual void changeEvent(QEvent*) override; - - void inputMethodEvent(QInputMethodEvent*) override; - QVariant inputMethodQuery(Qt::InputMethodQuery) const override; - static void closePopup(); - -public: - QtWidget(QtFrame& rFrame, Qt::WindowFlags f = Qt::WindowFlags()); - - QtFrame& frame() const { return m_rFrame; } - void endExtTextInput(); - - static bool handleEvent(QtFrame&, const QWidget&, QEvent*); - // key events might be propagated further down => call base on false - static inline bool handleKeyReleaseEvent(QtFrame&, const QWidget&, QKeyEvent*); - // mouse events are always accepted - static inline void handleMousePressEvent(const QtFrame&, const QMouseEvent*); - static inline void handleMouseReleaseEvent(const QtFrame&, const QMouseEvent*); -}; - -bool QtWidget::handleKeyReleaseEvent(QtFrame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent) -{ - return handleKeyEvent(rFrame, rWidget, pEvent, ButtonKeyState::Released); -} - -void QtWidget::handleMousePressEvent(const QtFrame& rFrame, const QMouseEvent* pEvent) -{ - handleMouseButtonEvent(rFrame, pEvent, ButtonKeyState::Pressed); -} - -void QtWidget::handleMouseReleaseEvent(const QtFrame& rFrame, const QMouseEvent* pEvent) -{ - handleMouseButtonEvent(rFrame, pEvent, ButtonKeyState::Released); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5XAccessible.hxx b/vcl/inc/qt5/Qt5XAccessible.hxx deleted file mode 100644 index 4f4285e8065b..000000000000 --- a/vcl/inc/qt5/Qt5XAccessible.hxx +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <vclpluginapi.h> - -#include <QtCore/QObject> - -#include <com/sun/star/accessibility/XAccessible.hpp> - -#include <vcl/window.hxx> - -class QtFrame; -class QtWidget; - -// Wrapper class to hold a css::accessibility::XAccessible object -// while being able to pass it as a QObject -class QtXAccessible : public QObject -{ - Q_OBJECT - -public: - QtXAccessible(css::uno::Reference<css::accessibility::XAccessible> xAccessible); - css::uno::Reference<css::accessibility::XAccessible> m_xAccessible; -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtAccessibleEventListener.hxx b/vcl/inc/qt5/QtAccessibleEventListener.hxx new file mode 100644 index 000000000000..a73f6d31f2f8 --- /dev/null +++ b/vcl/inc/qt5/QtAccessibleEventListener.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/lang/EventObject.hpp> + +#include "QtAccessibleWidget.hxx" + +#include <cppuhelper/implbase.hxx> + +class QtAccessibleEventListener final + : public cppu::WeakImplHelper<css::accessibility::XAccessibleEventListener> +{ +public: + QtAccessibleEventListener( + const css::uno::Reference<css::accessibility::XAccessible> xAccessible, + QtAccessibleWidget* pAccessibleWidget); + + virtual void SAL_CALL + notifyEvent(const css::accessibility::AccessibleEventObject& aEvent) override; + + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + +private: + css::uno::Reference<css::accessibility::XAccessible> m_xAccessible; + QtAccessibleWidget* m_pAccessibleWidget; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtAccessibleWidget.hxx b/vcl/inc/qt5/QtAccessibleWidget.hxx new file mode 100644 index 000000000000..102b5658fb28 --- /dev/null +++ b/vcl/inc/qt5/QtAccessibleWidget.hxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <vclpluginapi.h> + +#include <QtCore/QObject> +#include <QtCore/QPair> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVector> +#include <QtGui/QAccessible> +#include <QtGui/QAccessibleActionInterface> +#include <QtGui/QAccessibleInterface> +#include <QtGui/QAccessibleTableCellInterface> +#include <QtGui/QAccessibleTableInterface> +#include <QtGui/QAccessibleTextInterface> +#include <QtGui/QAccessibleValueInterface> +#include <QtGui/QColor> +#include <QtGui/QWindow> + +#include <com/sun/star/accessibility/XAccessible.hpp> + +namespace com::sun::star::accessibility +{ +class XAccessibleTable; +} + +class QtFrame; +class QtWidget; + +class QtAccessibleWidget final : public QObject, + public QAccessibleInterface, + public QAccessibleActionInterface, + public QAccessibleTextInterface, + public QAccessibleEditableTextInterface, + public QAccessibleTableCellInterface, + public QAccessibleTableInterface, + public QAccessibleValueInterface +{ + Q_OBJECT + +public: + QtAccessibleWidget(const css::uno::Reference<css::accessibility::XAccessible> xAccessible, + QObject* pObject); + QWindow* window() const override; + int childCount() const override; + int indexOfChild(const QAccessibleInterface* child) const override; + QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> + relations(QAccessible::Relation match = QAccessible::AllRelations) const override; + QAccessibleInterface* focusChild() const override; + + QRect rect() const override; + + QAccessibleInterface* parent() const override; + QAccessibleInterface* child(int index) const override; + + QString text(QAccessible::Text t) const override; + QAccessible::Role role() const override; + QAccessible::State state() const override; + + QColor foregroundColor() const override; + QColor backgroundColor() const override; + + bool isValid() const override; + QObject* object() const override; + void setText(QAccessible::Text t, const QString& text) override; + QAccessibleInterface* childAt(int x, int y) const override; + + void* interface_cast(QAccessible::InterfaceType t) override; + + // QAccessibleActionInterface + QStringList actionNames() const override; + void doAction(const QString& actionName) override; + QStringList keyBindingsForAction(const QString& actionName) const override; + + // QAccessibleTextInterface + void addSelection(int startOffset, int endOffset) override; + QString attributes(int offset, int* startOffset, int* endOffset) const override; + int characterCount() const override; + QRect characterRect(int offset) const override; + int cursorPosition() const override; + int offsetAtPoint(const QPoint& point) const override; + void removeSelection(int selectionIndex) override; + void scrollToSubstring(int startIndex, int endIndex) override; + void selection(int selectionIndex, int* startOffset, int* endOffset) const override; + int selectionCount() const override; + void setCursorPosition(int position) override; + void setSelection(int selectionIndex, int startOffset, int endOffset) override; + QString text(int startOffset, int endOffset) const override; + QString textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, + int* startOffset, int* endOffset) const override; + QString textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int* startOffset, + int* endOffset) const override; + QString textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, + int* startOffset, int* endOffset) const override; + + // QAccessibleEditableTextInterface + virtual void deleteText(int startOffset, int endOffset) override; + virtual void insertText(int offset, const QString& text) override; + virtual void replaceText(int startOffset, int endOffset, const QString& text) override; + + // QAccessibleValueInterface + QVariant currentValue() const override; + QVariant maximumValue() const override; + QVariant minimumStepSize() const override; + QVariant minimumValue() const override; + void setCurrentValue(const QVariant& value) override; + + // QAccessibleTableInterface + virtual QAccessibleInterface* caption() const override; + virtual QAccessibleInterface* cellAt(int row, int column) const override; + virtual int columnCount() const override; + virtual QString columnDescription(int column) const override; + virtual bool isColumnSelected(int column) const override; + virtual bool isRowSelected(int row) const override; + virtual void modelChange(QAccessibleTableModelChangeEvent* event) override; + virtual int rowCount() const override; + virtual QString rowDescription(int row) const override; + virtual bool selectColumn(int column) override; + virtual bool selectRow(int row) override; + virtual int selectedCellCount() const override; + virtual QList<QAccessibleInterface*> selectedCells() const override; + virtual int selectedColumnCount() const override; + virtual QList<int> selectedColumns() const override; + virtual int selectedRowCount() const override; + virtual QList<int> selectedRows() const override; + virtual QAccessibleInterface* summary() const override; + virtual bool unselectColumn(int column) override; + virtual bool unselectRow(int row) override; + + // QAccessibleTableCellInterface + virtual QList<QAccessibleInterface*> columnHeaderCells() const override; + virtual int columnIndex() const override; + virtual bool isSelected() const override; + virtual int columnExtent() const override; + virtual QList<QAccessibleInterface*> rowHeaderCells() const override; + virtual int rowExtent() const override; + virtual int rowIndex() const override; + virtual QAccessibleInterface* table() const override; + + // Factory + static QAccessibleInterface* customFactory(const QString& classname, QObject* object); + +private: + css::uno::Reference<css::accessibility::XAccessible> m_xAccessible; + css::uno::Reference<css::accessibility::XAccessibleContext> getAccessibleContextImpl() const; + css::uno::Reference<css::accessibility::XAccessibleTable> getAccessibleTableForParent() const; + QObject* m_pObject; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtBitmap.hxx b/vcl/inc/qt5/QtBitmap.hxx new file mode 100644 index 000000000000..a15deab29460 --- /dev/null +++ b/vcl/inc/qt5/QtBitmap.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <salbmp.hxx> + +#include <memory> + +class QImage; + +class QtBitmap final : public SalBitmap +{ + std::unique_ptr<QImage> m_pImage; + BitmapPalette m_aPalette; + +public: + QtBitmap(); + QtBitmap(const QImage& rQImage); + + const QImage* GetQImage() const { return m_pImage.get(); } + + virtual bool Create(const Size& rSize, vcl::PixelFormat ePixelFormat, + const BitmapPalette& rPal) override; + virtual bool Create(const SalBitmap& rSalBmp) override; + virtual bool Create(const SalBitmap& rSalBmp, SalGraphics* pGraphics) override; + virtual bool Create(const SalBitmap& rSalBmp, vcl::PixelFormat eNewPixelFormat) override; + virtual bool Create(const css::uno::Reference<css::rendering::XBitmapCanvas>& rBitmapCanvas, + Size& rSize, bool bMask = false) override; + virtual void Destroy() final override; + virtual Size GetSize() const override; + virtual sal_uInt16 GetBitCount() const override; + + virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override; + virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) override; + virtual bool GetSystemData(BitmapSystemData& rData) override; + + virtual bool ScalingSupported() const override; + virtual bool Scale(const double& rScaleX, const double& rScaleY, + BmpScaleFlag nScaleFlag) override; + virtual bool Replace(const Color& rSearchColor, const Color& rReplaceColor, + sal_uInt8 nTol) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtClipboard.hxx b/vcl/inc/qt5/QtClipboard.hxx new file mode 100644 index 000000000000..69c2f7a27d9e --- /dev/null +++ b/vcl/inc/qt5/QtClipboard.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp> +#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp> +#include <cppuhelper/compbase.hxx> + +#include <QtGui/QClipboard> + +/** + * This implementation has two main functions, which handle the clipboard content: + * the XClipboard::setContent function and the QClipboard::change signal handler. + * + * The first just sets the respective clipboard to the expected content from LO, + * the latter will handle any reported changes. + **/ +class QtClipboard final + : public QObject, + public cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard, + css::datatransfer::clipboard::XFlushableClipboard, + css::lang::XServiceInfo> +{ + Q_OBJECT + + osl::Mutex m_aMutex; + const OUString m_aClipboardName; + const QClipboard::Mode m_aClipboardMode; + // has to be set, if LO changes the QClipboard itself, so it won't instantly lose + // ownership by it's self-triggered QClipboard::changed handler + bool m_bOwnClipboardChange; + // true, if LO really wants to give up clipboard ownership + bool m_bDoClear; + + // if not empty, this holds the setContents provided XTransferable or a QtClipboardTransferable + css::uno::Reference<css::datatransfer::XTransferable> m_aContents; + // the owner of the current contents, which must be informed on content change + css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner; + std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> m_aListeners; + + static bool isOwner(const QClipboard::Mode aMode); + static bool isSupported(const QClipboard::Mode aMode); + + explicit QtClipboard(const OUString& aModeString, const QClipboard::Mode aMode); + +private Q_SLOTS: + void handleChanged(QClipboard::Mode mode); + void handleClearClipboard(); + +signals: + void clearClipboard(); + +public: + // factory function to construct only valid QtClipboard objects by name + static css::uno::Reference<css::uno::XInterface> create(const OUString& aModeString); + + // 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; + + // XClipboard + virtual css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override; + virtual void SAL_CALL setContents( + const css::uno::Reference<css::datatransfer::XTransferable>& xTrans, + const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner) + override; + virtual OUString SAL_CALL getName() override; + + // XClipboardEx + virtual sal_Int8 SAL_CALL getRenderingCapabilities() override; + + // XFlushableClipboard + virtual void SAL_CALL flushClipboard() override; + + // XClipboardNotifier + virtual void SAL_CALL addClipboardListener( + const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) + override; + virtual void SAL_CALL removeClipboardListener( + const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) + override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtData.hxx b/vcl/inc/qt5/QtData.hxx new file mode 100644 index 000000000000..ef8ee8f6f8f1 --- /dev/null +++ b/vcl/inc/qt5/QtData.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 <unx/gendata.hxx> + +#include <o3tl/enumarray.hxx> +#include <vcl/ptrstyle.hxx> +#include <memory> +#include <vclpluginapi.h> + +class QCursor; + +class VCLPLUG_QT5_PUBLIC QtData final : public GenericUnixSalData +{ + o3tl::enumarray<PointerStyle, std::unique_ptr<QCursor>> m_aCursors; + +public: + explicit QtData(SalInstance* pInstance); + virtual ~QtData() override; + + virtual void ErrorTrapPush() override; + virtual bool ErrorTrapPop(bool bIgnoreError = true) override; + + QCursor& getCursor(PointerStyle ePointerStyle); + + static bool noNativeControls(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtDragAndDrop.hxx b/vcl/inc/qt5/QtDragAndDrop.hxx new file mode 100644 index 000000000000..0ca1ebfb83aa --- /dev/null +++ b/vcl/inc/qt5/QtDragAndDrop.hxx @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include <com/sun/star/datatransfer/dnd/XDragSource.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/compbase.hxx> + +class QtFrame; + +class QtDragSource final + : public cppu::WeakComponentImplHelper<css::datatransfer::dnd::XDragSource, + css::lang::XInitialization, css::lang::XServiceInfo> +{ + osl::Mutex m_aMutex; + QtFrame* m_pFrame; + css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> m_xListener; + +public: + QtDragSource() + : WeakComponentImplHelper(m_aMutex) + , m_pFrame(nullptr) + { + } + + virtual ~QtDragSource() override; + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported() override; + virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction) override; + virtual void SAL_CALL startDrag( + const css::datatransfer::dnd::DragGestureEvent& trigger, sal_Int8 sourceActions, + sal_Int32 cursor, sal_Int32 image, + const css::uno::Reference<css::datatransfer::XTransferable>& transferable, + const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& listener) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override; + void deinitialize(); + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + void fire_dragEnd(sal_Int8 nAction, bool bSuccessful); +}; + +class QtDropTarget final + : public cppu::WeakComponentImplHelper<css::datatransfer::dnd::XDropTarget, + css::datatransfer::dnd::XDropTargetDragContext, + css::datatransfer::dnd::XDropTargetDropContext, + css::lang::XInitialization, css::lang::XServiceInfo> +{ + osl::Mutex m_aMutex; + QtFrame* m_pFrame; + sal_Int8 m_nDropAction; + bool m_bActive; + sal_Int8 m_nDefaultActions; + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> m_aListeners; + bool m_bDropSuccessful; + +public: + QtDropTarget(); + virtual ~QtDropTarget() override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArgs) override; + void deinitialize(); + + // XDropTarget + virtual void SAL_CALL addDropTargetListener( + const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>&) override; + virtual void SAL_CALL removeDropTargetListener( + const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>&) override; + virtual sal_Bool SAL_CALL isActive() override; + virtual void SAL_CALL setActive(sal_Bool active) override; + virtual sal_Int8 SAL_CALL getDefaultActions() override; + virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override; + + // XDropTargetDragContext + virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) override; + virtual void SAL_CALL rejectDrag() override; + + // XDropTargetDropContext + virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) override; + virtual void SAL_CALL rejectDrop() override; + virtual void SAL_CALL dropComplete(sal_Bool success) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + void fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde); + void fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte); + void fire_dragOver(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde); + void fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde); + + sal_Int8 proposedDropAction() const { return m_nDropAction; } + bool dropSuccessful() const { return m_bDropSuccessful; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtFilePicker.hxx b/vcl/inc/qt5/QtFilePicker.hxx new file mode 100644 index 000000000000..ffad1acc6f2f --- /dev/null +++ b/vcl/inc/qt5/QtFilePicker.hxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vclpluginapi.h> + +#include <cppuhelper/compbase.hxx> + +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <osl/conditn.hxx> +#include <osl/mutex.hxx> +#include <unotools/resmgr.hxx> + +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QHash> +#include <QtWidgets/QFileDialog> + +#include <memory> + +class QComboBox; +class QGridLayout; +class QLabel; +class QWidget; + +typedef ::cppu::WeakComponentImplHelper<css::frame::XTerminateListener, css::lang::XInitialization, + css::lang::XServiceInfo, css::ui::dialogs::XFilePicker3, + css::ui::dialogs::XFilePickerControlAccess, + css::ui::dialogs::XFolderPicker2> + QtFilePicker_Base; + +class VCLPLUG_QT5_PUBLIC QtFilePicker : public QObject, public QtFilePicker_Base +{ + Q_OBJECT + +private: + css::uno::Reference<css::uno::XComponentContext> m_context; + + css::uno::Reference<css::ui::dialogs::XFilePickerListener> m_xListener; + + osl::Mutex m_aHelperMutex; ///< mutex used by the WeakComponentImplHelper + + QStringList m_aNamedFilterList; ///< to keep the original sequence + QHash<QString, QString> m_aTitleToFilterMap; + // to retrieve the filename extension for a given filter + QHash<QString, QString> m_aNamedFilterToExtensionMap; + QString m_aCurrentFilter; + + QGridLayout* m_pLayout; ///< layout for extra custom controls + QHash<sal_Int16, QWidget*> m_aCustomWidgetsMap; ///< map of SAL control ID's to widget + + const bool m_bIsFolderPicker; + + QWidget* m_pParentWidget; + +protected: + std::unique_ptr<QFileDialog> m_pFileDialog; ///< the file picker dialog + QWidget* m_pExtraControls; ///< widget to contain extra custom controls + +public: + // use non-native file dialog by default; there's no easy way to add custom widgets + // in a generic way in the native one + explicit QtFilePicker(css::uno::Reference<css::uno::XComponentContext> const& context, + QFileDialog::FileMode, bool bUseNative = false); + virtual ~QtFilePicker() override; + + // XFilePickerNotifier + virtual void SAL_CALL addFilePickerListener( + const css::uno::Reference<css::ui::dialogs::XFilePickerListener>& xListener) override; + virtual void SAL_CALL removeFilePickerListener( + const css::uno::Reference<css::ui::dialogs::XFilePickerListener>& xListener) override; + + // XFilterManager functions + virtual void SAL_CALL appendFilter(const OUString& rTitle, const OUString& rFilter) override; + virtual void SAL_CALL setCurrentFilter(const OUString& rTitle) override; + virtual OUString SAL_CALL getCurrentFilter() override; + + // XFilterGroupManager functions + virtual void SAL_CALL + appendFilterGroup(const OUString& rGroupTitle, + const css::uno::Sequence<css::beans::StringPair>& rFilters) override; + + // XCancellable + virtual void SAL_CALL cancel() override; + + // XExecutableDialog functions + virtual void SAL_CALL setTitle(const OUString& rTitle) override; + virtual sal_Int16 SAL_CALL execute() override; + + // XFilePicker functions + virtual void SAL_CALL setMultiSelectionMode(sal_Bool bMode) override; + virtual void SAL_CALL setDefaultName(const OUString& rName) override; + virtual void SAL_CALL setDisplayDirectory(const OUString& rDirectory) override; + virtual OUString SAL_CALL getDisplayDirectory() override; + virtual css::uno::Sequence<OUString> SAL_CALL getFiles() override; + + // XFilePickerControlAccess functions + virtual void SAL_CALL setValue(sal_Int16 nControlId, sal_Int16 nControlAction, + const css::uno::Any& rValue) override; + virtual css::uno::Any SAL_CALL getValue(sal_Int16 nControlId, + sal_Int16 nControlAction) override; + virtual void SAL_CALL enableControl(sal_Int16 nControlId, sal_Bool bEnable) override; + virtual void SAL_CALL setLabel(sal_Int16 nControlId, const OUString& rLabel) override; + virtual OUString SAL_CALL getLabel(sal_Int16 nControlId) override; + + // XFilePicker2 functions + virtual css::uno::Sequence<OUString> SAL_CALL getSelectedFiles() override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override; + + // XEventListener + void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + using cppu::WeakComponentImplHelperBase::disposing; + + // 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; + + // XFolderPicker functions + virtual OUString SAL_CALL getDirectory() override; + virtual void SAL_CALL setDescription(const OUString& rDescription) override; + + // XTerminateListener + void SAL_CALL queryTermination(const css::lang::EventObject& aEvent) override; + void SAL_CALL notifyTermination(const css::lang::EventObject& aEvent) override; + +protected: + virtual void addCustomControl(sal_Int16 controlId); + void setCustomControlWidgetLayout(QGridLayout* pLayout) { m_pLayout = pLayout; } + +private: + QtFilePicker(const QtFilePicker&) = delete; + QtFilePicker& operator=(const QtFilePicker&) = delete; + + static QString getResString(TranslateId pRedId); + static css::uno::Any handleGetListValue(const QComboBox* pWidget, sal_Int16 nControlAction); + static void handleSetListValue(QComboBox* pQComboBox, sal_Int16 nAction, + const css::uno::Any& rValue); + +private Q_SLOTS: + // emit XFilePickerListener controlStateChanged event + void filterSelected(const QString&); + // emit XFilePickerListener fileSelectionChanged event + void currentChanged(const QString&); + // (un)set automatic file extension + virtual void updateAutomaticFileExtension(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtFont.hxx b/vcl/inc/qt5/QtFont.hxx new file mode 100644 index 000000000000..f2b250f33d18 --- /dev/null +++ b/vcl/inc/qt5/QtFont.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 <sal/config.h> + +#include <fontinstance.hxx> + +#include <QtGui/QFont> + +#include "QtFontFace.hxx" + +class QtFont final : public QFont, public LogicalFontInstance +{ + friend rtl::Reference<LogicalFontInstance> + QtFontFace::CreateFontInstance(const vcl::font::FontSelectPattern&) const; + + bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override; + bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; + + virtual hb_font_t* ImplInitHbFont() override; + + explicit QtFont(const PhysicalFontFace&, const vcl::font::FontSelectPattern&); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtFontFace.hxx b/vcl/inc/qt5/QtFontFace.hxx new file mode 100644 index 000000000000..2f15a26e308b --- /dev/null +++ b/vcl/inc/qt5/QtFontFace.hxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <vclpluginapi.h> +#include <PhysicalFontFace.hxx> + +#include <tools/ref.hxx> +#include <vcl/fontcapabilities.hxx> +#include <vcl/fontcharmap.hxx> + +#include <QtCore/QString> +#include <QtGui/QFont> + +class FontAttributes; +namespace vcl::font +{ +class FontSelectPattern; +} + +class QtFontFace final : public PhysicalFontFace +{ +public: + static QtFontFace* fromQFont(const QFont& rFont); + static QtFontFace* fromQFontDatabase(const QString& aFamily, const QString& aStyle); + static void fillAttributesFromQFont(const QFont& rFont, FontAttributes& rFA); + + VCLPLUG_QT5_PUBLIC static FontWeight toFontWeight(const int nWeight); + VCLPLUG_QT5_PUBLIC static FontWidth toFontWidth(const int nStretch); + VCLPLUG_QT5_PUBLIC static FontItalic toFontItalic(const QFont::Style eStyle); + + sal_IntPtr GetFontId() const override; + + QFont CreateFont() const; + int GetFontTable(const char pTagName[5], unsigned char*) const; + + FontCharMapRef GetFontCharMap() const override; + bool GetFontCapabilities(vcl::FontCapabilities&) const override; + bool HasChar(sal_uInt32 cChar) const; + + rtl::Reference<LogicalFontInstance> + CreateFontInstance(const vcl::font::FontSelectPattern& rFSD) const override; + +private: + typedef enum { Font, FontDB } FontIdType; + + QtFontFace(const QtFontFace&); + QtFontFace(const FontAttributes&, const QString& rFontID, const FontIdType); + + const QString m_aFontId; + const FontIdType m_eFontIdType; + mutable FontCharMapRef m_xCharMap; + mutable vcl::FontCapabilities m_aFontCapabilities; + mutable bool m_bFontCapabilitiesRead; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtFrame.hxx b/vcl/inc/qt5/QtFrame.hxx new file mode 100644 index 000000000000..c584c1d750f9 --- /dev/null +++ b/vcl/inc/qt5/QtFrame.hxx @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <config_vclplug.h> + +#include <salframe.hxx> +#include <vclpluginapi.h> + +#include "QtTools.hxx" + +#include <headless/svpgdi.hxx> +#include <vcl/svapp.hxx> +#include <vcl/sysdata.hxx> + +#include <QtCore/QObject> + +#if QT5_USING_X11 +#include <unx/screensaverinhibitor.hxx> +// any better way to get rid of the X11 / Qt type clashes? +#undef Bool +#undef CursorShape +#undef Expose +#undef KeyPress +#undef KeyRelease +#undef FocusIn +#undef FocusOut +#undef FontChange +#undef None +#undef Status +#undef Unsorted +#endif + +class QtDragSource; +class QtDropTarget; +class QtGraphics; +class QtInstance; +class QtMainWindow; +class QtMenu; +class QtSvpGraphics; + +class QDragMoveEvent; +class QDropEvent; +class QImage; +class QMimeData; +class QPaintDevice; +class QScreen; +class QWidget; + +class VCLPLUG_QT5_PUBLIC QtFrame : public QObject, public SalFrame +{ + Q_OBJECT + + friend class QtWidget; + + QWidget* m_pQWidget; + QtMainWindow* m_pTopLevel; + + const bool m_bUseCairo; + std::unique_ptr<QImage> m_pQImage; + std::unique_ptr<QtGraphics> m_pQtGraphics; + UniqueCairoSurface m_pSurface; + std::unique_ptr<QtSvpGraphics> m_pSvpGraphics; + DamageHandler m_aDamageHandler; + QRegion m_aRegion; + bool m_bNullRegion; + + bool m_bGraphicsInUse; + SalFrameStyleFlags m_nStyle; + QtFrame* m_pParent; + PointerStyle m_ePointerStyle; + + SystemEnvData m_aSystemData; + + QtDragSource* m_pDragSource; + QtDropTarget* m_pDropTarget; + bool m_bInDrag; + + bool m_bDefaultSize; + bool m_bDefaultPos; + bool m_bFullScreen; + bool m_bFullScreenSpanAll; + sal_uInt32 m_nRestoreScreen; + QRect m_aRestoreGeometry; + +#if QT5_USING_X11 + ScreenSaverInhibitor m_ScreenSaverInhibitor; + ModKeyFlags m_nKeyModifiers; +#endif + + LanguageType m_nInputLanguage; + + void SetDefaultPos(); + Size CalcDefaultSize(); + void SetDefaultSize(); + + bool isChild(bool bPlug = true, bool bSysChild = true) const + { + SalFrameStyleFlags nMask = SalFrameStyleFlags::NONE; + if (bPlug) + nMask |= SalFrameStyleFlags::PLUG; + if (bSysChild) + nMask |= SalFrameStyleFlags::SYSTEMCHILD; + return bool(m_nStyle & nMask); + } + + bool isWindow() const; + QWindow* windowHandle() const; + QScreen* screen() const; + bool isMinimized() const; + bool isMaximized() const; + void SetWindowStateImpl(Qt::WindowStates eState); + + void fixICCCMwindowGroup(); + +public: + QtFrame(QtFrame* pParent, SalFrameStyleFlags nSalFrameStyle, bool bUseCairo); + virtual ~QtFrame() override; + + QWidget* GetQWidget() const { return m_pQWidget; } + QtMainWindow* GetTopLevelWindow() const { return m_pTopLevel; } + QWidget* asChild() const; + qreal devicePixelRatioF() const; + + void Damage(sal_Int32 nExtentsX, sal_Int32 nExtentsY, sal_Int32 nExtentsWidth, + sal_Int32 nExtentsHeight) const; + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics(SalGraphics* pGraphics) override; + + virtual bool PostEvent(std::unique_ptr<ImplSVEvent> pData) override; + + virtual void SetTitle(const OUString& rTitle) override; + virtual void SetIcon(sal_uInt16 nIcon) override; + virtual void SetMenu(SalMenu* pMenu) override; + virtual void DrawMenuBar() override; + + virtual void registerDragSource(QtDragSource* pDragSource); + virtual void deregisterDragSource(QtDragSource const* pDragSource); + virtual void registerDropTarget(QtDropTarget* pDropTarget); + virtual void deregisterDropTarget(QtDropTarget const* pDropTarget); + + void handleDragLeave(); + void handleDragMove(QDragMoveEvent* pEvent); + void handleDrop(QDropEvent* pEvent); + + virtual void SetExtendedFrameStyle(SalExtStyle nExtStyle) override; + virtual void Show(bool bVisible, bool bNoActivate = false) override; + virtual void SetMinClientSize(tools::Long nWidth, tools::Long nHeight) override; + virtual void SetMaxClientSize(tools::Long nWidth, tools::Long nHeight) override; + virtual void SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + sal_uInt16 nFlags) override; + virtual void GetClientSize(tools::Long& rWidth, tools::Long& rHeight) override; + virtual void GetWorkArea(tools::Rectangle& rRect) override; + virtual SalFrame* GetParent() const override; + virtual void SetModal(bool bModal) override; + virtual bool GetModal() const override; + virtual void SetWindowState(const SalFrameState* pState) override; + virtual bool GetWindowState(SalFrameState* pState) override; + virtual void ShowFullScreen(bool bFullScreen, sal_Int32 nDisplay) override; + virtual void StartPresentation(bool bStart) override; + virtual void SetAlwaysOnTop(bool bOnTop) override; + virtual void ToTop(SalFrameToTop nFlags) override; + virtual void SetPointer(PointerStyle ePointerStyle) override; + virtual void CaptureMouse(bool bMouse) override; + virtual void SetPointerPos(tools::Long nX, tools::Long nY) override; + virtual bool ShowTooltip(const OUString& rText, const tools::Rectangle& rHelpArea) override; + using SalFrame::Flush; + virtual void Flush() override; + virtual void SetInputContext(SalInputContext* pContext) override; + virtual void EndExtTextInput(EndExtTextInputFlags nFlags) override; + virtual OUString GetKeyName(sal_uInt16 nKeyCode) override; + virtual bool MapUnicodeToKeyCode(sal_Unicode aUnicode, LanguageType aLangType, + vcl::KeyCode& rKeyCode) override; + virtual LanguageType GetInputLanguage() override; + virtual void UpdateSettings(AllSettings& rSettings) override; + virtual void Beep() override; + virtual const SystemEnvData* GetSystemData() const override { return &m_aSystemData; } + virtual SalPointerState GetPointerState() override; + virtual KeyIndicatorState GetIndicatorState() override; + virtual void SimulateKeyPress(sal_uInt16 nKeyCode) override; + virtual void SetParent(SalFrame* pNewParent) override; + virtual void SetPluginParent(SystemParentData* pNewParent) override; + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion(sal_uInt32 nRects) override; + virtual void UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) override; + virtual void EndSetClipRegion() override; + + virtual void SetScreenNumber(unsigned int) override; + virtual void SetApplicationID(const OUString&) override; + + inline bool CallCallback(SalEvent nEvent, const void* pEvent) const; + + void setInputLanguage(LanguageType); + inline bool isPopup() const; +}; + +inline bool QtFrame::CallCallback(SalEvent nEvent, const void* pEvent) const +{ + SolarMutexGuard aGuard; + return SalFrame::CallCallback(nEvent, pEvent); +} + +inline bool QtFrame::isPopup() const +{ + return ((m_nStyle & SalFrameStyleFlags::FLOAT) + && !(m_nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtGraphics.hxx b/vcl/inc/qt5/QtGraphics.hxx new file mode 100644 index 000000000000..db08f8418844 --- /dev/null +++ b/vcl/inc/qt5/QtGraphics.hxx @@ -0,0 +1,247 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <salgdi.hxx> + +#include <memory> + +#include <QtGui/QPainter> +#include <QtGui/QPainterPath> +#include <QtGui/QRegion> + +#include "QtGraphicsBase.hxx" + +class PhysicalFontCollection; +class QImage; +class QPushButton; +class QtFont; +class QtFontFace; +class QtFrame; +class QtPainter; + +class QtGraphicsBackend final : public SalGraphicsImpl, public QtGraphicsBase +{ + friend class QtPainter; + + QtFrame* m_pFrame; + QImage* m_pQImage; + QRegion m_aClipRegion; + QPainterPath m_aClipPath; + Color m_aLineColor; + Color m_aFillColor; + QPainter::CompositionMode m_eCompositionMode; + +public: + QtGraphicsBackend(QtFrame* pFrame, QImage* pQImage); + ~QtGraphicsBackend() override; + + void Init() override {} + + QImage* getQImage() { return m_pQImage; } + + void setQImage(QImage* pQImage) { m_pQImage = pQImage; } + + void freeResources() override {} + + OUString getRenderBackendName() const override { return "qt5"; } + + bool setClipRegion(vcl::Region const& rRegion) override; + void ResetClipRegion() override; + + sal_uInt16 GetBitCount() const override; + + tools::Long GetGraphicsWidth() const override; + + void SetLineColor() override; + void SetLineColor(Color nColor) override; + void SetFillColor() override; + void SetFillColor(Color nColor) override; + void SetXORMode(bool bSet, bool bInvertOnly) override; + void SetROPLineColor(SalROPColor nROPColor) override; + void SetROPFillColor(SalROPColor nROPColor) override; + + void drawPixel(tools::Long nX, tools::Long nY) override; + void drawPixel(tools::Long nX, tools::Long nY, Color nColor) override; + + void drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2) override; + void drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight) override; + void drawPolyLine(sal_uInt32 nPoints, const Point* pPointArray) override; + void drawPolygon(sal_uInt32 nPoints, const Point* pPointArray) override; + void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, + const Point** pPointArray) override; + + bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, double fTransparency) override; + + bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&, + double fTransparency, double fLineWidth, const std::vector<double>* pStroke, + basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + + bool drawPolyLineBezier(sal_uInt32 nPoints, const Point* pPointArray, + const PolyFlags* pFlagArray) override; + + bool drawPolygonBezier(sal_uInt32 nPoints, const Point* pPointArray, + const PolyFlags* pFlagArray) override; + + bool drawPolyPolygonBezier(sal_uInt32 nPoly, const sal_uInt32* pPoints, + const Point* const* pPointArray, + const PolyFlags* const* pFlagArray) override; + + void copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY, + tools::Long nSrcWidth, tools::Long nSrcHeight, bool bWindowInvalidate) override; + + void copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) override; + + void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) override; + + void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap) override; + + void drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + Color nMaskColor) override; + + std::shared_ptr<SalBitmap> getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) override; + + Color getPixel(tools::Long nX, tools::Long nY) override; + + void invert(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + SalInvert nFlags) override; + + void invert(sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags) override; + + bool drawEPS(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + void* pPtr, sal_uInt32 nSize) override; + + bool blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap) override; + + bool blendAlphaBitmap(const SalTwoRect&, const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, const SalBitmap& rAlphaBitmap) override; + + bool drawAlphaBitmap(const SalTwoRect&, const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap) override; + + bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap, double fAlpha) override; + + bool hasFastDrawTransformedBitmap() const override; + + bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + sal_uInt8 nTransparency) override; + + bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; + bool implDrawGradient(basegfx::B2DPolyPolygon const& rPolyPolygon, + SalGradient const& rGradient) override; + + bool supportsOperation(OutDevSupportType eType) const override; + +private: + void drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage); +}; + +class QtGraphics final : public SalGraphicsAutoDelegateToImpl, public QtGraphicsBase +{ + friend class QtBitmap; + + std::unique_ptr<QtGraphicsBackend> m_pBackend; + + QtFrame* m_pFrame; + + rtl::Reference<QtFont> m_pTextStyle[MAX_FALLBACK]; + Color m_aTextColor; + + QtGraphics(QtFrame* pFrame, QImage* pQImage); + + void drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage); + + void handleDamage(const tools::Rectangle&) override; + +public: + QtGraphics(QtFrame* pFrame) + : QtGraphics(pFrame, nullptr) + { + } + QtGraphics(QImage* pQImage) + : QtGraphics(nullptr, pQImage) + { + } + virtual ~QtGraphics() override; + + QImage* getQImage() { return m_pBackend->getQImage(); } + + void ChangeQImage(QImage* pImage); + + virtual SalGraphicsImpl* GetImpl() const override; + virtual SystemGraphicsData GetGraphicsData() const override; + virtual OUString getRenderBackendName() const override + { + return m_pBackend->getRenderBackendName(); + } + +#if ENABLE_CAIRO_CANVAS + virtual bool SupportsCairo() const override; + virtual cairo::SurfaceSharedPtr + CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, + int width, int height) const override; + virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, + const BitmapSystemData& rData, + const Size& rSize) const override; + virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, + const basegfx::B2ISize& rSize) const override; +#endif // ENABLE_CAIRO_CANVAS + + // GDI + + virtual void GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) override; + + // Text rendering + font support + + virtual void SetTextColor(Color nColor) override; + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) override; + virtual void GetFontMetric(ImplFontMetricDataRef&, int nFallbackLevel) override; + virtual FontCharMapRef GetFontCharMap() const override; + virtual bool GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const override; + virtual void GetDevFontList(PhysicalFontCollection*) override; + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont(PhysicalFontCollection*, const OUString& rFileURL, + const OUString& rFontName) override; + virtual bool CreateFontSubset(const OUString& rToFile, const PhysicalFontFace* pFont, + const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, + sal_Int32* pWidths, int nGlyphs, + FontSubsetInfo& rInfo // out parameter + ) override; + + virtual const void* GetEmbedFontData(const PhysicalFontFace*, tools::Long* pDataLen) override; + virtual void FreeEmbedFontData(const void* pData, tools::Long nDataLen) override; + + virtual void GetGlyphWidths(const PhysicalFontFace*, bool bVertical, + std::vector<sal_Int32>& rWidths, Ucs2UIntMap& rUnicodeEnc) override; + + virtual std::unique_ptr<GenericSalLayout> GetTextLayout(int nFallbackLevel) override; + virtual void DrawTextLayout(const GenericSalLayout&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtGraphicsBase.hxx b/vcl/inc/qt5/QtGraphicsBase.hxx new file mode 100644 index 000000000000..73c39fb5ba80 --- /dev/null +++ b/vcl/inc/qt5/QtGraphicsBase.hxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <QtWidgets/QApplication> + +class QtGraphicsBase +{ + qreal m_fDPR; + +public: + QtGraphicsBase() + : m_fDPR(qApp ? qApp->devicePixelRatio() : 1.0) + { + } + + void setDevicePixelRatioF(qreal fDPR) { m_fDPR = fDPR; } + + qreal devicePixelRatioF() const { return m_fDPR; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtGraphics_Controls.hxx b/vcl/inc/qt5/QtGraphics_Controls.hxx new file mode 100644 index 000000000000..17039f9d6038 --- /dev/null +++ b/vcl/inc/qt5/QtGraphics_Controls.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vclpluginapi.h> +#include <WidgetDrawInterface.hxx> + +#include <memory> + +#include <QtGui/QImage> +#include <QtGui/QPainter> +#include <QtGui/QRegion> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QStyle> +#include <QtWidgets/QStyleOption> + +class QtGraphicsBase; + +class QtGraphics_Controls final : public vcl::WidgetDrawInterface +{ + std::unique_ptr<QImage> m_image; + QRect m_lastPopupRect; + QtGraphicsBase const& m_rGraphics; + +public: + QtGraphics_Controls(const QtGraphicsBase& rGraphics); + + QImage* getImage() { return m_image.get(); } + + bool isNativeControlSupported(ControlType nType, ControlPart nPart) override; + bool hitTestNativeControl(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, const Point& aPos, + bool& rIsInside) override; + bool drawNativeControl(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue, const OUString& aCaption, + const Color& rBackgroundColor) override; + bool getNativeControlRegion(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue, const OUString& aCaption, + tools::Rectangle& rNativeBoundingRegion, + tools::Rectangle& rNativeContentRegion) override; + +private: + static int pixelMetric(QStyle::PixelMetric metric, const QStyleOption* option = nullptr); + static QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption* option, + const QSize& contentsSize); + static QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex* option, + QStyle::SubControl subControl); + static QRect subElementRect(QStyle::SubElement element, const QStyleOption* option); + + void draw(QStyle::ControlElement element, QStyleOption& rOption, QImage* image, + const Color& rBackgroundColor, QStyle::State const state = QStyle::State_None, + QRect rect = QRect()); + void draw(QStyle::PrimitiveElement element, QStyleOption& rOption, QImage* image, + const Color& rBackgroundColor, QStyle::State const state = QStyle::State_None, + QRect rect = QRect()); + void draw(QStyle::ComplexControl element, QStyleOptionComplex& rOption, QImage* image, + const Color& rBackgroundColor, QStyle::State const state = QStyle::State_None); + void drawFrame(QStyle::PrimitiveElement element, QImage* image, const Color& rBackGroundColor, + QStyle::State const& state, bool bClip = true, + QStyle::PixelMetric eLineMetric = QStyle::PM_DefaultFrameWidth); + + static void fillQStyleOptionTab(const ImplControlValue& value, QStyleOptionTab& sot); + void fullQStyleOptionTabWidgetFrame(QStyleOptionTabWidgetFrame& option, bool bDownscale); + + enum class Round + { + Floor, + Ceil, + }; + + int downscale(int value, Round eRound); + int upscale(int value, Round eRound); + QRect downscale(const QRect& rect); + QRect upscale(const QRect& rect); + QSize downscale(const QSize& size, Round eRound); + QSize upscale(const QSize& size, Round eRound); + QPoint upscale(const QPoint& point, Round eRound); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtInstance.hxx b/vcl/inc/qt5/QtInstance.hxx new file mode 100644 index 000000000000..8ec1d98b387e --- /dev/null +++ b/vcl/inc/qt5/QtInstance.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vclpluginapi.h> +#include <unx/geninst.h> +#include <salusereventlist.hxx> +#include <vcl/timer.hxx> + +#include <osl/conditn.hxx> + +#include <QtCore/QObject> + +#include <cstdlib> +#include <functional> +#include <memory> +#include <vector> + +#include "QtFilePicker.hxx" + +class QtTimer; + +class QApplication; +class SalYieldMutex; +class SalFrame; + +struct StdFreeCStr +{ + void operator()(char* arg) const noexcept { std::free(arg); } +}; +using FreeableCStr = std::unique_ptr<char[], StdFreeCStr>; + +class VCLPLUG_QT5_PUBLIC QtInstance : public QObject, + public SalGenericInstance, + public SalUserEventList +{ + Q_OBJECT + + osl::Condition m_aWaitingYieldCond; + const bool m_bUseCairo; + QtTimer* m_pTimer; + bool m_bSleeping; + std::unordered_map<OUString, css::uno::Reference<css::uno::XInterface>> m_aClipboards; + + std::unique_ptr<QApplication> m_pQApplication; + std::vector<FreeableCStr> m_pFakeArgvFreeable; + std::unique_ptr<char* []> m_pFakeArgv; + std::unique_ptr<int> m_pFakeArgc; + + Timer m_aUpdateStyleTimer; + bool m_bUpdateFonts; + + DECL_LINK(updateStyleHdl, Timer*, void); + void AfterAppInit() override; + +private Q_SLOTS: + bool ImplYield(bool bWait, bool bHandleAllCurrentEvents); + static void deleteObjectLater(QObject* pObject); + static void localeChanged(); + +Q_SIGNALS: + bool ImplYieldSignal(bool bWait, bool bHandleAllCurrentEvents); + void deleteObjectLaterSignal(QObject* pObject); + +protected: + virtual rtl::Reference<QtFilePicker> + createPicker(css::uno::Reference<css::uno::XComponentContext> const& context, + QFileDialog::FileMode); + bool useCairo() const { return m_bUseCairo; } + // encodes cairo usage and Qt platform name into the ToolkitName + OUString constructToolkitID(std::u16string_view sTKname); + +public: + explicit QtInstance(std::unique_ptr<QApplication>& pQApp, bool bUseCairo = false); + virtual ~QtInstance() override; + + // handle common SalInstance setup + static void AllocFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, + std::unique_ptr<int>& rFakeArgc, + std::vector<FreeableCStr>& rFakeArgvFreeable); + void MoveFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, std::unique_ptr<int>& rFakeArgc, + std::vector<FreeableCStr>& rFakeArgvFreeable); + static std::unique_ptr<QApplication> CreateQApplication(int& nArgc, char** pArgv); + + void RunInMainThread(std::function<void()> func); + + virtual SalFrame* CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) override; + virtual SalFrame* CreateChildFrame(SystemParentData* pParent, + SalFrameStyleFlags nStyle) override; + virtual void DestroyFrame(SalFrame* pFrame) override; + + virtual SalObject* CreateObject(SalFrame* pParent, SystemWindowData* pWindowData, + bool bShow) override; + virtual void DestroyObject(SalObject* pObject) override; + + virtual std::unique_ptr<SalVirtualDevice> + CreateVirtualDevice(SalGraphics& rGraphics, tools::Long& nDX, tools::Long& nDY, + DeviceFormat eFormat, const SystemGraphicsData* pData = nullptr) override; + + virtual SalInfoPrinter* CreateInfoPrinter(SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData) override; + virtual void DestroyInfoPrinter(SalInfoPrinter* pPrinter) override; + virtual std::unique_ptr<SalPrinter> CreatePrinter(SalInfoPrinter* pInfoPrinter) override; + virtual void GetPrinterQueueInfo(ImplPrnQueueList* pList) override; + virtual void GetPrinterQueueState(SalPrinterQueueInfo* pInfo) override; + virtual OUString GetDefaultPrinter() override; + virtual void PostPrintersChanged() override; + + virtual std::unique_ptr<SalMenu> CreateMenu(bool, Menu*) override; + virtual std::unique_ptr<SalMenuItem> CreateMenuItem(const SalItemParams&) override; + + virtual SalTimer* CreateSalTimer() override; + virtual SalSystem* CreateSalSystem() override; + virtual std::shared_ptr<SalBitmap> CreateSalBitmap() override; + + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; + virtual bool AnyInput(VclInputFlags nType) override; + +// so we fall back to the default abort, instead of duplicating it... +#ifndef EMSCRIPTEN + virtual OpenGLContext* CreateOpenGLContext() override; +#endif + + virtual OUString GetConnectionIdentifier() override; + + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, + const OUString& rDocumentService) override; + + virtual std::unique_ptr<GenPspGraphics> CreatePrintGraphics() override; + + virtual bool IsMainThread() const override; + + virtual void TriggerUserEventProcessing() override; + virtual void ProcessEvent(SalUserEvent aEvent) override; + + bool hasNativeFileSelection() const override { return true; } + css::uno::Reference<css::ui::dialogs::XFilePicker2> + createFilePicker(const css::uno::Reference<css::uno::XComponentContext>&) override; + css::uno::Reference<css::ui::dialogs::XFolderPicker2> + createFolderPicker(const css::uno::Reference<css::uno::XComponentContext>&) override; + + virtual css::uno::Reference<css::uno::XInterface> + CreateClipboard(const css::uno::Sequence<css::uno::Any>& i_rArguments) override; + virtual css::uno::Reference<css::uno::XInterface> CreateDragSource() override; + virtual css::uno::Reference<css::uno::XInterface> CreateDropTarget() override; + + void UpdateStyle(bool bFontsChanged); + + void* CreateGStreamerSink(const SystemChildWindow*) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtMainWindow.hxx b/vcl/inc/qt5/QtMainWindow.hxx new file mode 100644 index 000000000000..29621310b731 --- /dev/null +++ b/vcl/inc/qt5/QtMainWindow.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QMainWindow> + +#include "QtFrame.hxx" + +class QtMainWindow final : public QMainWindow +{ + Q_OBJECT + + QtFrame& m_rFrame; + + virtual void closeEvent(QCloseEvent* pEvent) override; + void moveEvent(QMoveEvent*) override; + +public: + QtMainWindow(QtFrame& rFrame, Qt::WindowFlags f = Qt::WindowFlags()); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtMenu.hxx b/vcl/inc/qt5/QtMenu.hxx new file mode 100644 index 000000000000..55275ae6e099 --- /dev/null +++ b/vcl/inc/qt5/QtMenu.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <salmenu.hxx> + +#include <QtCore/QObject> + +#include <memory> + +class MenuItemList; +class QAction; +class QActionGroup; +class QPushButton; +class QMenu; +class QMenuBar; +class QtMenuItem; +class QtFrame; + +/* + * QtMenu can represent + * (1) the top-level menu of a menubar, in which case 'mbMenuBar' is true and + * 'mpQMenuBar' refers to the corresponding QMenuBar + * (2) another kind of menu (like a PopupMenu), in which case the corresponding QMenu + * object is instantiated and owned by this QtMenu (held in 'mpOwnedQMenu'). + * (3) a "submenu" in an existing menu (like (1)), in which case the corresponding + * QMenu object is owned by the corresponding QtMenuItem. + * + * For (2) and (3), member 'mpQMenu' points to the corresponding QMenu object. + */ +class QtMenu : public QObject, public SalMenu +{ + Q_OBJECT +private: + std::vector<QtMenuItem*> maItems; + VclPtr<Menu> mpVCLMenu; + QtMenu* mpParentSalMenu; + QtFrame* mpFrame; + bool mbMenuBar; + QMenuBar* mpQMenuBar; + // self-created QMenu that this QtMenu represents, if applicable (s. comment for class) + std::unique_ptr<QMenu> mpOwnedQMenu; + // pointer to QMenu owned by the corresponding QtMenuItem or self (-> mpOwnedQMenu) + QMenu* mpQMenu; + QPushButton* mpCloseButton; + QMetaObject::Connection maCloseButtonConnection; + + void DoFullMenuUpdate(Menu* pMenuBar); + static void NativeItemText(OUString& rItemText); + + void InsertMenuItem(QtMenuItem* pSalMenuItem, unsigned nPos); + + void ReinitializeActionGroup(unsigned nPos); + void ResetAllActionGroups(); + void UpdateActionGroupItem(const QtMenuItem* pSalMenuItem); + +public: + QtMenu(bool bMenuBar); + + virtual bool VisibleMenuBar() override; // must return TRUE to actually DISPLAY native menu bars + + virtual void InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos) override; + virtual void RemoveItem(unsigned nPos) override; + virtual void SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos) override; + virtual void SetFrame(const SalFrame* pFrame) override; + const QtFrame* GetFrame() const; + virtual void ShowMenuBar(bool bVisible) override; + virtual bool ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect, + FloatWinPopupFlags nFlags) override; + QtMenu* GetTopLevel(); + virtual void SetItemBits(unsigned nPos, MenuItemBits nBits) override; + virtual void CheckItem(unsigned nPos, bool bCheck) override; + virtual void EnableItem(unsigned nPos, bool bEnable) override; + virtual void ShowItem(unsigned nPos, bool bShow) override; + virtual void SetItemText(unsigned nPos, SalMenuItem* pSalMenuItem, + const OUString& rText) override; + virtual void SetItemImage(unsigned nPos, SalMenuItem* pSalMenuItem, + const Image& rImage) override; + virtual void SetAccelerator(unsigned nPos, SalMenuItem* pSalMenuItem, + const vcl::KeyCode& rKeyCode, const OUString& rKeyName) override; + virtual void GetSystemMenuData(SystemMenuData* pData) override; + virtual void ShowCloseButton(bool bShow) override; + + void SetMenu(Menu* pMenu) { mpVCLMenu = pMenu; } + Menu* GetMenu() { return mpVCLMenu; } + unsigned GetItemCount() const { return maItems.size(); } + QtMenuItem* GetItemAtPos(unsigned nPos) { return maItems[nPos]; } + +private slots: + static void slotMenuTriggered(QtMenuItem* pQItem); + static void slotMenuAboutToShow(QtMenuItem* pQItem); + static void slotMenuAboutToHide(QtMenuItem* pQItem); + void slotCloseDocument(); +}; + +class QtMenuItem : public SalMenuItem +{ +public: + QtMenuItem(const SalItemParams*); + + QAction* getAction() const; + + QtMenu* mpParentMenu; // The menu into which this menu item is inserted + QtMenu* mpSubMenu; // Submenu of this item (if defined) + std::unique_ptr<QAction> mpAction; // action corresponding to this item + std::unique_ptr<QMenu> mpMenu; // menu corresponding to this item + std::shared_ptr<QActionGroup> mpActionGroup; // empty if it's a separator element + sal_uInt16 mnId; // Item ID + MenuItemType mnType; // Item type + bool mbVisible; // Item visibility. + bool mbEnabled; // Item active. + Image maImage; // Item image +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtObject.hxx b/vcl/inc/qt5/QtObject.hxx new file mode 100644 index 000000000000..328946e4388e --- /dev/null +++ b/vcl/inc/qt5/QtObject.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <salobj.hxx> +#include <vcl/sysdata.hxx> + +#include <QtCore/QObject> +#include <QtGui/QRegion> +#include <QtGui/QWindow> + +class QtFrame; +class QWidget; + +class QtObject final : public QObject, public SalObject +{ + Q_OBJECT + + SystemEnvData m_aSystemData; + QtFrame* m_pParent; + QWidget* m_pQWidget; // main widget, container + QWindow* m_pQWindow; // contained window, used for opengl rendering + QRegion m_pRegion; + +public: + QtObject(QtFrame* pParent, bool bShow); + ~QtObject() override; + + QtFrame* frame() const { return m_pParent; } + QWidget* widget() const { return m_pQWidget; } + QWindow* windowHandle() const { return m_pQWindow; } + + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion(sal_uInt32 nRects) override; + virtual void UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) override; + virtual void EndSetClipRegion() override; + + virtual void SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) override; + virtual void Show(bool bVisible) override; + + virtual void SetForwardKey(bool bEnable) override; + + virtual const SystemEnvData* GetSystemData() const override { return &m_aSystemData; } +}; + +class QtObjectWindow final : public QWindow +{ + QtObject& m_rParent; + + bool event(QEvent*) override; + void focusInEvent(QFocusEvent*) override; + void focusOutEvent(QFocusEvent*) override; + void mousePressEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent*) override; + // keyPressEvent(QKeyEvent*) is handled via event(QEvent*); see comment in QtWidget::event + void keyReleaseEvent(QKeyEvent*) override; + +public: + explicit QtObjectWindow(QtObject& rParent); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtOpenGLContext.hxx b/vcl/inc/qt5/QtOpenGLContext.hxx new file mode 100644 index 000000000000..8036d50777b9 --- /dev/null +++ b/vcl/inc/qt5/QtOpenGLContext.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vcl/opengl/OpenGLContext.hxx> + +class QWindow; +class QOpenGLContext; + +class QtOpenGLContext final : public OpenGLContext +{ +public: + virtual void initWindow() override; + +private: + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } + virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } + virtual bool ImplInit() override; + + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual bool isCurrent() override; + virtual bool isAnyCurrent() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; + + static bool g_bAnyCurrent; + + GLWindow m_aGLWin; + + QWindow* m_pWindow; + QOpenGLContext* m_pContext; +}; diff --git a/vcl/inc/qt5/QtPainter.hxx b/vcl/inc/qt5/QtPainter.hxx new file mode 100644 index 000000000000..9702a19bdbe4 --- /dev/null +++ b/vcl/inc/qt5/QtPainter.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 <QtCore/QRectF> +#include <QtGui/QPainter> +#include <QtWidgets/QWidget> + +#include "QtFrame.hxx" +#include "QtGraphics.hxx" + +class QtPainter final : public QPainter +{ + QtGraphicsBackend& m_rGraphics; + QRegion m_aRegion; + +public: + QtPainter(QtGraphicsBackend& rGraphics, bool bPrepareBrush = false, + sal_uInt8 nTransparency = 255); + ~QtPainter() + { + if (m_rGraphics.m_pFrame && !m_aRegion.isEmpty()) + m_rGraphics.m_pFrame->GetQWidget()->update(m_aRegion); + } + + void update(int nx, int ny, int nw, int nh) + { + if (m_rGraphics.m_pFrame) + m_aRegion += scaledQRect({ nx, ny, nw, nh }, 1 / m_rGraphics.devicePixelRatioF()); + } + + void update(const QRect& rRect) + { + if (m_rGraphics.m_pFrame) + m_aRegion += scaledQRect(rRect, 1 / m_rGraphics.devicePixelRatioF()); + } + + void update(const QRectF& rRectF) + { + if (m_rGraphics.m_pFrame) + update(scaledQRect(rRectF.toAlignedRect(), 1 / m_rGraphics.devicePixelRatioF())); + } + + void update() + { + if (m_rGraphics.m_pFrame) + m_aRegion += m_rGraphics.m_pFrame->GetQWidget()->rect(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtPrinter.hxx b/vcl/inc/qt5/QtPrinter.hxx new file mode 100644 index 000000000000..5aacfd44ec05 --- /dev/null +++ b/vcl/inc/qt5/QtPrinter.hxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <unx/genprn.h> + +class SalFrame; + +class QtPrinter final : public PspSalPrinter +{ +public: + QtPrinter(SalInfoPrinter* pInfoPrinter); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtSvpGraphics.hxx b/vcl/inc/qt5/QtSvpGraphics.hxx new file mode 100644 index 000000000000..23f3ccc82abd --- /dev/null +++ b/vcl/inc/qt5/QtSvpGraphics.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vclpluginapi.h> +#include <headless/svpgdi.hxx> + +#include "QtGraphicsBase.hxx" + +class QtFrame; + +class VCLPLUG_QT5_PUBLIC QtSvpGraphics final : public SvpSalGraphics, public QtGraphicsBase +{ + QtFrame* const m_pFrame; + + void handleDamage(const tools::Rectangle&) override; + +public: + QtSvpGraphics(QtFrame* pFrame); + ~QtSvpGraphics() override; + + void updateQWidget() const; + +#if ENABLE_CAIRO_CANVAS + bool SupportsCairo() const override; + cairo::SurfaceSharedPtr + CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, + int height) const override; +#endif // ENABLE_CAIRO_CANVAS + + virtual void GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) override; + + virtual OUString getRenderBackendName() const override { return "qt5svp"; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtSvpSurface.hxx b/vcl/inc/qt5/QtSvpSurface.hxx new file mode 100644 index 000000000000..2c2b29cff386 --- /dev/null +++ b/vcl/inc/qt5/QtSvpSurface.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <sal/config.h> + +#include <vcl/cairo.hxx> + +class QtSvpGraphics; +class OutputDevice; + +namespace cairo +{ +class QtSvpSurface final : public Surface +{ + const QtSvpGraphics* m_pGraphics; + cairo_t* const m_pCairoContext; + CairoSurfaceSharedPtr m_pSurface; + +public: + /// takes over ownership of passed cairo_surface + explicit QtSvpSurface(const CairoSurfaceSharedPtr& pSurface); + /// create surface on subarea of given drawable + explicit QtSvpSurface(const QtSvpGraphics* pGraphics, int x, int y, int width, int height); + ~QtSvpSurface() override; + + // Surface interface + CairoSharedPtr getCairo() const override; + CairoSurfaceSharedPtr getCairoSurface() const override { return m_pSurface; } + SurfaceSharedPtr getSimilar(int nContentType, int width, int height) const override; + + VclPtr<VirtualDevice> createVirtualDevice() const override; + void flush() const override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtSystem.hxx b/vcl/inc/qt5/QtSystem.hxx new file mode 100644 index 000000000000..6992e381c4c4 --- /dev/null +++ b/vcl/inc/qt5/QtSystem.hxx @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <unx/gensys.h> + +class QtSystem final : public SalGenericSystem +{ +public: + virtual unsigned int GetDisplayScreenCount() override; + virtual tools::Rectangle GetDisplayScreenPosSizePixel(unsigned int nScreen) override; + virtual int ShowNativeDialog(const OUString& rTitle, const OUString& rMessage, + const std::vector<OUString>& rButtons) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtTimer.hxx b/vcl/inc/qt5/QtTimer.hxx new file mode 100644 index 000000000000..204b1bfe43ad --- /dev/null +++ b/vcl/inc/qt5/QtTimer.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <saltimer.hxx> +#include <QtCore/QTimer> + +class QtTimer final : public QObject, public SalTimer +{ + Q_OBJECT + + QTimer m_aTimer; + +private Q_SLOTS: + void timeoutActivated(); + void startTimer(int); + void stopTimer(); + +Q_SIGNALS: + void startTimerSignal(int); + void stopTimerSignal(); + +public: + QtTimer(); + + int remainingTime() const { return m_aTimer.remainingTime(); } + + virtual void Start(sal_uInt64 nMS) override; + virtual void Stop() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtTools.hxx b/vcl/inc/qt5/QtTools.hxx new file mode 100644 index 000000000000..7221a8ce8dc6 --- /dev/null +++ b/vcl/inc/qt5/QtTools.hxx @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <QtCore/QPoint> +#include <QtCore/QRect> +#include <QtCore/QSize> +#include <QtCore/QString> +#include <QtGui/QImage> + +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <tools/color.hxx> +#include <tools/gen.hxx> +#include <vcl/bitmap/BitmapTypes.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include <memory> + +class Image; +class QImage; + +inline OUString toOUString(const QString& s) +{ + // QString stores UTF16, just like OUString + return OUString(reinterpret_cast<const sal_Unicode*>(s.data()), s.length()); +} + +inline QString toQString(const OUString& s) +{ + return QString::fromUtf16(s.getStr(), s.getLength()); +} + +inline QRect toQRect(const tools::Rectangle& rRect) +{ + return QRect(rRect.Left(), rRect.Top(), rRect.GetWidth(), rRect.GetHeight()); +} + +inline QRect toQRect(const tools::Rectangle& rRect, const qreal fScale) +{ + return QRect(floor(rRect.Left() * fScale), floor(rRect.Top() * fScale), + ceil(rRect.GetWidth() * fScale), ceil(rRect.GetHeight() * fScale)); +} + +inline QRect scaledQRect(const QRect& rRect, const qreal fScale) +{ + return QRect(floor(rRect.x() * fScale), floor(rRect.y() * fScale), ceil(rRect.width() * fScale), + ceil(rRect.height() * fScale)); +} + +inline tools::Rectangle toRectangle(const QRect& rRect) +{ + return tools::Rectangle(rRect.left(), rRect.top(), rRect.right(), rRect.bottom()); +} + +inline QSize toQSize(const Size& rSize) { return QSize(rSize.Width(), rSize.Height()); } + +inline Size toSize(const QSize& rSize) { return Size(rSize.width(), rSize.height()); } + +inline Point toPoint(const QPoint& rPoint) { return Point(rPoint.x(), rPoint.y()); } + +inline QColor toQColor(const Color& rColor) +{ + return QColor(rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue(), rColor.GetAlpha()); +} + +Qt::DropActions toQtDropActions(sal_Int8 dragOperation); +sal_Int8 toVclDropActions(Qt::DropActions dragOperation); +sal_Int8 toVclDropAction(Qt::DropAction dragOperation); +Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation); + +inline QList<int> toQList(const css::uno::Sequence<sal_Int32>& aSequence) +{ + QList<int> aList; + for (sal_Int32 i : aSequence) + { + aList.append(i); + } + return aList; +} + +constexpr QImage::Format Qt_DefaultFormat32 = QImage::Format_ARGB32; + +inline QImage::Format getBitFormat(vcl::PixelFormat ePixelFormat) +{ + switch (ePixelFormat) + { + case vcl::PixelFormat::N1_BPP: + return QImage::Format_Mono; + case vcl::PixelFormat::N8_BPP: + return QImage::Format_Indexed8; + case vcl::PixelFormat::N24_BPP: + return QImage::Format_RGB888; + case vcl::PixelFormat::N32_BPP: + return Qt_DefaultFormat32; + default: + std::abort(); + break; + } + return QImage::Format_Invalid; +} + +inline sal_uInt16 getFormatBits(QImage::Format eFormat) +{ + switch (eFormat) + { + case QImage::Format_Mono: + return 1; + case QImage::Format_Indexed8: + return 8; + case QImage::Format_RGB888: + return 24; + case Qt_DefaultFormat32: + case QImage::Format_ARGB32_Premultiplied: + return 32; + default: + std::abort(); + return 0; + } +} + +typedef struct _cairo_surface cairo_surface_t; +struct CairoDeleter +{ + void operator()(cairo_surface_t* pSurface) const; +}; + +typedef std::unique_ptr<cairo_surface_t, CairoDeleter> UniqueCairoSurface; + +sal_uInt16 GetKeyModCode(Qt::KeyboardModifiers eKeyModifiers); +sal_uInt16 GetMouseModCode(Qt::MouseButtons eButtons); + +QImage toQImage(const Image& rImage); + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const QString& rString) +{ + return stream << toOUString(rString); +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const QRect& rRect) +{ + return stream << toRectangle(rRect); +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const QSize& rSize) +{ + return stream << toSize(rSize); +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const QPoint& rPoint) +{ + return stream << toPoint(rPoint); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtTransferable.hxx b/vcl/inc/qt5/QtTransferable.hxx new file mode 100644 index 000000000000..8a4410535359 --- /dev/null +++ b/vcl/inc/qt5/QtTransferable.hxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include <cppuhelper/compbase.hxx> +#include <com/sun/star/datatransfer/XTransferable.hpp> + +#include <QtCore/QMimeData> +#include <QtCore/QStringList> +#include <QtGui/QClipboard> + +/** + * QtTransferable classes are used to read QMimeData via the XTransferable + * interface. All the functionality is already implemented in the QtTransferable. + * + * The specialisations map to the two users, which provide QMimeData: the Clipboard + * and the Drag'n'Drop functionality. + * + * LO itself seem to just accept "text/plain;charset=utf-16", so it relies on the + * backend to convert to this charset, but still offers "text/plain" itself. + * + * It's the "mirror" interface of the QtMimeData, which is defined below. + **/ +class QtTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransferable> +{ + QtTransferable(const QtTransferable&) = delete; + + const QMimeData* m_pMimeData; + osl::Mutex m_aMutex; + bool m_bConvertFromLocale; + css::uno::Sequence<css::datatransfer::DataFlavor> m_aMimeTypeSeq; + +public: + QtTransferable(const QMimeData* pMimeData); + const QMimeData* mimeData() const { return m_pMimeData; } + + css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override; + sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; + css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override; +}; + +/** + * The QClipboard's QMimeData is volatile. As written in the QClipboard::mimeData + * documentation, "the pointer returned might become invalidated when the contents + * of the clipboard changes". Therefore it can just be accessed reliably inside + * the QClipboard's object thread, which is the QApplication's thread, so all of + * the access has to go through RunInMainThread(). + * + * If we detect a QMimeData change, we simply drop reporting any content. In theory + * we can recover in the case where there hadn't been any calls of the XTransferable + * interface, but currently we don't. But we ensure to never report mixed content, + * so we'll just cease operation on QMimeData change. + **/ +class QtClipboardTransferable final : public QtTransferable +{ + // to detect in-flight QMimeData changes + const QClipboard::Mode m_aMode; + + bool hasInFlightChanged() const; + +public: + explicit QtClipboardTransferable(const QClipboard::Mode aMode, const QMimeData* pMimeData); + + // these are the same then QtTransferable, except they go through RunInMainThread + css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override; + sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; + css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override; +}; + +/** + * Convenience typedef for better code readability + * + * This just uses the QMimeData provided by the QWidgets D'n'D events. + **/ +typedef QtTransferable QtDnDTransferable; + +/** + * A lazy loading QMimeData for XTransferable reads + * + * This is an interface class to make a XTransferable read accessible as a + * QMimeData. The mime data is just stored inside the XTransferable, never + * in the QMimeData itself! It's objects are just used for QClipboard to read + * the XTransferable data. + * + * Like XTransferable itself, this class should be considered an immutable + * container for mime data. There is no need to ever set any of its data. + * + * LO will offer at least UTF-16, if there is a viable text representation. + * If LO misses to offer a UTF-8 or a locale encoded string, these objects + * will offer them themselves and convert from UTF-16 on demand. + * + * It's the "mirror" interface of the QtTransferable. + **/ +class QtMimeData final : public QMimeData +{ + friend class QtClipboardTransferable; + + const css::uno::Reference<css::datatransfer::XTransferable> m_aContents; + mutable bool m_bHaveNoCharset; // = uses the locale charset + mutable bool m_bHaveUTF8; + mutable QStringList m_aMimeTypeList; + + QVariant retrieveData(const QString& mimeType, QVariant::Type type) const override; + +public: + explicit QtMimeData(const css::uno::Reference<css::datatransfer::XTransferable>& aContents); + + bool hasFormat(const QString& mimeType) const override; + QStringList formats() const override; + + bool deepCopy(QMimeData** const) const; + + css::datatransfer::XTransferable* xTransferable() const { return m_aContents.get(); } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtVirtualDevice.hxx b/vcl/inc/qt5/QtVirtualDevice.hxx new file mode 100644 index 000000000000..2481f63d0657 --- /dev/null +++ b/vcl/inc/qt5/QtVirtualDevice.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <salvd.hxx> + +#include <memory> +#include <vector> + +#include <QtCore/QSize> + +class QtGraphics; +class QImage; +enum class DeviceFormat; + +class QtVirtualDevice final : public SalVirtualDevice +{ + std::vector<QtGraphics*> m_aGraphics; + std::unique_ptr<QImage> m_pImage; + QSize m_aFrameSize; + double m_fScale; + +public: + QtVirtualDevice(double fScale); + + // SalVirtualDevice + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics(SalGraphics* pGraphics) override; + + virtual bool SetSize(tools::Long nNewDX, tools::Long nNewDY) override; + virtual bool SetSizeUsingBuffer(tools::Long nNewDX, tools::Long nNewDY, + sal_uInt8* pBuffer) override; + + // SalGeometryProvider + virtual tools::Long GetWidth() const override; + virtual tools::Long GetHeight() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtWidget.hxx b/vcl/inc/qt5/QtWidget.hxx new file mode 100644 index 000000000000..801cd290ff88 --- /dev/null +++ b/vcl/inc/qt5/QtWidget.hxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <QtWidgets/QWidget> +#include <rtl/ustring.hxx> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> + +class QInputEvent; +class QtFrame; +class QtObject; +struct SalAbstractMouseEvent; + +class QtWidget : public QWidget +{ + Q_OBJECT + + QtFrame& m_rFrame; + bool m_bNonEmptyIMPreeditSeen; + int m_nDeltaX; + int m_nDeltaY; + + enum class ButtonKeyState + { + Pressed, + Released + }; + + static void commitText(QtFrame&, const QString& aText); + static bool handleKeyEvent(QtFrame&, const QWidget&, QKeyEvent*, const ButtonKeyState); + static void handleMouseButtonEvent(const QtFrame&, const QMouseEvent*, const ButtonKeyState); + static void fillSalAbstractMouseEvent(const QtFrame& rFrame, const QInputEvent* pQEvent, + const QPoint& rPos, Qt::MouseButtons eButtons, int nWidth, + SalAbstractMouseEvent& aSalEvent); + + virtual bool event(QEvent*) override; + + virtual void focusInEvent(QFocusEvent*) override; + virtual void focusOutEvent(QFocusEvent*) override; + // keyPressEvent(QKeyEvent*) is handled via event(QEvent*); see comment + virtual void keyReleaseEvent(QKeyEvent*) override; + virtual void mouseMoveEvent(QMouseEvent*) override; + virtual void mousePressEvent(QMouseEvent*) override; + virtual void mouseReleaseEvent(QMouseEvent*) override; + virtual void dragEnterEvent(QDragEnterEvent*) override; + virtual void dragLeaveEvent(QDragLeaveEvent*) override; + virtual void dragMoveEvent(QDragMoveEvent*) override; + virtual void dropEvent(QDropEvent*) override; + virtual void moveEvent(QMoveEvent*) override; + virtual void paintEvent(QPaintEvent*) override; + virtual void resizeEvent(QResizeEvent*) override; + virtual void showEvent(QShowEvent*) override; + virtual void wheelEvent(QWheelEvent*) override; + virtual void closeEvent(QCloseEvent*) override; + virtual void changeEvent(QEvent*) override; + + void inputMethodEvent(QInputMethodEvent*) override; + QVariant inputMethodQuery(Qt::InputMethodQuery) const override; + static void closePopup(); + +public: + QtWidget(QtFrame& rFrame, Qt::WindowFlags f = Qt::WindowFlags()); + + QtFrame& frame() const { return m_rFrame; } + void endExtTextInput(); + + static bool handleEvent(QtFrame&, const QWidget&, QEvent*); + // key events might be propagated further down => call base on false + static inline bool handleKeyReleaseEvent(QtFrame&, const QWidget&, QKeyEvent*); + // mouse events are always accepted + static inline void handleMousePressEvent(const QtFrame&, const QMouseEvent*); + static inline void handleMouseReleaseEvent(const QtFrame&, const QMouseEvent*); +}; + +bool QtWidget::handleKeyReleaseEvent(QtFrame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent) +{ + return handleKeyEvent(rFrame, rWidget, pEvent, ButtonKeyState::Released); +} + +void QtWidget::handleMousePressEvent(const QtFrame& rFrame, const QMouseEvent* pEvent) +{ + handleMouseButtonEvent(rFrame, pEvent, ButtonKeyState::Pressed); +} + +void QtWidget::handleMouseReleaseEvent(const QtFrame& rFrame, const QMouseEvent* pEvent) +{ + handleMouseButtonEvent(rFrame, pEvent, ButtonKeyState::Released); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/QtXAccessible.hxx b/vcl/inc/qt5/QtXAccessible.hxx new file mode 100644 index 000000000000..4f4285e8065b --- /dev/null +++ b/vcl/inc/qt5/QtXAccessible.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <vclpluginapi.h> + +#include <QtCore/QObject> + +#include <com/sun/star/accessibility/XAccessible.hpp> + +#include <vcl/window.hxx> + +class QtFrame; +class QtWidget; + +// Wrapper class to hold a css::accessibility::XAccessible object +// while being able to pass it as a QObject +class QtXAccessible : public QObject +{ + Q_OBJECT + +public: + QtXAccessible(css::uno::Reference<css::accessibility::XAccessible> xAccessible); + css::uno::Reference<css::accessibility::XAccessible> m_xAccessible; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5AccessibleEventListener.cxx b/vcl/qt5/Qt5AccessibleEventListener.cxx deleted file mode 100644 index 6f0e3bf827f8..000000000000 --- a/vcl/qt5/Qt5AccessibleEventListener.cxx +++ /dev/null @@ -1,173 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5AccessibleEventListener.hxx> - -#include <sal/log.hxx> - -#include <com/sun/star/accessibility/AccessibleEventId.hpp> - -#include <QtGui/QAccessible> - -using namespace css; -using namespace css::accessibility; -using namespace css::lang; -using namespace css::uno; - -QtAccessibleEventListener::QtAccessibleEventListener(const Reference<XAccessible> xAccessible, - QtAccessibleWidget* pAccessibleWidget) - : m_xAccessible(xAccessible) - , m_pAccessibleWidget(pAccessibleWidget) -{ -} - -void QtAccessibleEventListener::notifyEvent(const css::accessibility::AccessibleEventObject& aEvent) -{ - QAccessibleInterface* pQAccessibleInterface = m_pAccessibleWidget; - - Reference<XAccessible> xChild; - switch (aEvent.EventId) - { - case AccessibleEventId::NAME_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::NameChanged)); - return; - case AccessibleEventId::DESCRIPTION_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::DescriptionChanged)); - return; - case AccessibleEventId::ACTION_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActionChanged)); - return; - case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActiveDescendantChanged)); - return; - case AccessibleEventId::CHILD: - { - QAccessible::Event event = QAccessible::InvalidEvent; - if (aEvent.OldValue >>= xChild) - event = QAccessible::ObjectDestroyed; - if (aEvent.NewValue >>= xChild) - event = QAccessible::ObjectCreated; - if (event != QAccessible::InvalidEvent) - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, event)); - return; - } - case AccessibleEventId::SELECTION_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection)); - return; - case AccessibleEventId::VISIBLE_DATA_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::VisibleDataChanged)); - return; - case AccessibleEventId::TEXT_SELECTION_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection)); - return; - case AccessibleEventId::TEXT_ATTRIBUTE_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::AttributeChanged)); - return; - case AccessibleEventId::TABLE_CAPTION_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableCaptionChanged)); - return; - case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: - QAccessible::updateAccessibility(new QAccessibleEvent( - pQAccessibleInterface, QAccessible::TableColumnDescriptionChanged)); - return; - case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableColumnHeaderChanged)); - return; - case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: - QAccessible::updateAccessibility(new QAccessibleEvent( - pQAccessibleInterface, QAccessible::TableRowDescriptionChanged)); - return; - case AccessibleEventId::TABLE_ROW_HEADER_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableRowHeaderChanged)); - return; - case AccessibleEventId::TABLE_SUMMARY_CHANGED: - case AccessibleEventId::CARET_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableSummaryChanged)); - return; - case AccessibleEventId::SELECTION_CHANGED_ADD: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionAdd)); - return; - case AccessibleEventId::SELECTION_CHANGED_REMOVE: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionRemove)); - return; - case AccessibleEventId::SELECTION_CHANGED_WITHIN: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionWithin)); - return; - case AccessibleEventId::PAGE_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::PageChanged)); - return; - case AccessibleEventId::SECTION_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::SectionChanged)); - return; - case AccessibleEventId::TEXT_CHANGED: - case AccessibleEventId::COLUMN_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::TextColumnChanged)); - return; - case AccessibleEventId::BOUNDRECT_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::LocationChanged)); - return; - case AccessibleEventId::STATE_CHANGED: - QAccessible::updateAccessibility( - new QAccessibleEvent(pQAccessibleInterface, QAccessible::ForegroundChanged)); - return; - case AccessibleEventId::ROLE_CHANGED: - case AccessibleEventId::INVALIDATE_ALL_CHILDREN: - case AccessibleEventId::VALUE_CHANGED: - case AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED: - case AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED: - case AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED: - case AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED: - case AccessibleEventId::LABEL_FOR_RELATION_CHANGED: - case AccessibleEventId::LABELED_BY_RELATION_CHANGED: - case AccessibleEventId::MEMBER_OF_RELATION_CHANGED: - case AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED: - case AccessibleEventId::HYPERTEXT_CHANGED: - case AccessibleEventId::TABLE_MODEL_CHANGED: - case AccessibleEventId::LISTBOX_ENTRY_EXPANDED: - case AccessibleEventId::LISTBOX_ENTRY_COLLAPSED: - case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS: - default: - SAL_WARN("vcl.qt5", "Unmapped AccessibleEventId: " << aEvent.EventId); - return; - } -} - -void QtAccessibleEventListener::disposing(const EventObject& /* Source */) {} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5AccessibleWidget.cxx b/vcl/qt5/Qt5AccessibleWidget.cxx deleted file mode 100644 index 5dcb30b2da6e..000000000000 --- a/vcl/qt5/Qt5AccessibleWidget.cxx +++ /dev/null @@ -1,1476 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5AccessibleWidget.hxx> -#include <Qt5AccessibleWidget.moc> - -#include <QtGui/QAccessibleInterface> - -#include <Qt5AccessibleEventListener.hxx> -#include <Qt5Frame.hxx> -#include <Qt5Tools.hxx> -#include <Qt5Widget.hxx> -#include <Qt5XAccessible.hxx> - -#include <com/sun/star/accessibility/AccessibleRelationType.hpp> -#include <com/sun/star/accessibility/AccessibleRole.hpp> -#include <com/sun/star/accessibility/AccessibleScrollType.hpp> -#include <com/sun/star/accessibility/AccessibleStateType.hpp> -#include <com/sun/star/accessibility/AccessibleTextType.hpp> -#include <com/sun/star/accessibility/XAccessible.hpp> -#include <com/sun/star/accessibility/XAccessibleAction.hpp> -#include <com/sun/star/accessibility/XAccessibleComponent.hpp> -#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> -#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> -#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> -#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp> -#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> -#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> -#include <com/sun/star/accessibility/XAccessibleTable.hpp> -#include <com/sun/star/accessibility/XAccessibleTableSelection.hpp> -#include <com/sun/star/accessibility/XAccessibleText.hpp> -#include <com/sun/star/accessibility/XAccessibleValue.hpp> -#include <com/sun/star/awt/FontWeight.hpp> -#include <com/sun/star/beans/PropertyValue.hpp> -#include <com/sun/star/lang/DisposedException.hpp> -#include <com/sun/star/uno/Sequence.hxx> - -#include <comphelper/AccessibleImplementationHelper.hxx> -#include <o3tl/any.hxx> -#include <sal/log.hxx> - -using namespace css; -using namespace css::accessibility; -using namespace css::beans; -using namespace css::uno; - -QtAccessibleWidget::QtAccessibleWidget(const Reference<XAccessible> xAccessible, QObject* pObject) - : m_xAccessible(xAccessible) - , m_pObject(pObject) -{ - Reference<XAccessibleContext> xContext = xAccessible->getAccessibleContext(); - Reference<XAccessibleEventBroadcaster> xBroadcaster(xContext, UNO_QUERY); - if (xBroadcaster.is()) - { - Reference<XAccessibleEventListener> xListener( - new QtAccessibleEventListener(xAccessible, this)); - xBroadcaster->addAccessibleEventListener(xListener); - } -} - -Reference<XAccessibleContext> QtAccessibleWidget::getAccessibleContextImpl() const -{ - Reference<XAccessibleContext> xAc; - - if (m_xAccessible.is()) - { - try - { - xAc = m_xAccessible->getAccessibleContext(); - } - catch (css::lang::DisposedException /*ex*/) - { - SAL_WARN("vcl.qt5", "Accessible context disposed already"); - } - // sometimes getAccessibleContext throws also RuntimeException if context is no longer alive - catch (css::uno::RuntimeException /*ex*/) - { - // so let's catch it here, cuz otherwise soffice falls flat on its face - // with FatalError and nothing else - SAL_WARN("vcl.qt5", "Accessible context no longer alive"); - } - } - - return xAc; -} - -css::uno::Reference<css::accessibility::XAccessibleTable> -QtAccessibleWidget::getAccessibleTableForParent() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return nullptr; - - Reference<XAccessible> xParent = xAcc->getAccessibleParent(); - if (!xParent.is()) - return nullptr; - - Reference<XAccessibleContext> xParentContext = xParent->getAccessibleContext(); - if (!xParentContext.is()) - return nullptr; - - return Reference<XAccessibleTable>(xParentContext, UNO_QUERY); -} - -QWindow* QtAccessibleWidget::window() const { return nullptr; } - -int QtAccessibleWidget::childCount() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return 0; - - return xAc->getAccessibleChildCount(); -} - -int QtAccessibleWidget::indexOfChild(const QAccessibleInterface* /* child */) const { return 0; } - -namespace -{ -sal_Int16 lcl_matchQtTextBoundaryType(QAccessible::TextBoundaryType boundaryType) -{ - switch (boundaryType) - { - case QAccessible::CharBoundary: - return com::sun::star::accessibility::AccessibleTextType::CHARACTER; - case QAccessible::WordBoundary: - return com::sun::star::accessibility::AccessibleTextType::WORD; - case QAccessible::SentenceBoundary: - return com::sun::star::accessibility::AccessibleTextType::SENTENCE; - case QAccessible::ParagraphBoundary: - return com::sun::star::accessibility::AccessibleTextType::PARAGRAPH; - case QAccessible::LineBoundary: - return com::sun::star::accessibility::AccessibleTextType::LINE; - case QAccessible::NoBoundary: - // assert here, better handle it directly at call site - assert(false - && "No match for QAccessible::NoBoundary, handle it separately at call site."); - break; - default: - break; - } - - SAL_WARN("vcl.qt5", "Unmatched text boundary type: " << boundaryType); - return -1; -} - -QAccessible::Relation lcl_matchUnoRelation(short relationType) -{ - switch (relationType) - { - case AccessibleRelationType::CONTROLLER_FOR: - return QAccessible::Controller; - case AccessibleRelationType::CONTROLLED_BY: - return QAccessible::Controlled; - case AccessibleRelationType::LABEL_FOR: - return QAccessible::Label; - case AccessibleRelationType::LABELED_BY: - return QAccessible::Labelled; - case AccessibleRelationType::INVALID: - case AccessibleRelationType::CONTENT_FLOWS_FROM: - case AccessibleRelationType::CONTENT_FLOWS_TO: - case AccessibleRelationType::MEMBER_OF: - case AccessibleRelationType::SUB_WINDOW_OF: - case AccessibleRelationType::NODE_CHILD_OF: - case AccessibleRelationType::DESCRIBED_BY: - default: - SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType); - return {}; - } -} - -short lcl_matchQtRelation(QAccessible::Relation relationType) -{ - switch (relationType) - { - case QAccessible::Controller: - return AccessibleRelationType::CONTROLLER_FOR; - case QAccessible::Controlled: - return AccessibleRelationType::CONTROLLED_BY; - case QAccessible::Label: - return AccessibleRelationType::LABEL_FOR; - case QAccessible::Labelled: - return AccessibleRelationType::LABELED_BY; - default: - SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType); - } - return 0; -} - -void lcl_appendRelation(QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>* relations, - AccessibleRelation aRelation) -{ - QAccessible::Relation aQRelation = lcl_matchUnoRelation(aRelation.RelationType); - sal_uInt32 nTargetCount = aRelation.TargetSet.getLength(); - - for (sal_uInt32 i = 0; i < nTargetCount; i++) - { - Reference<XAccessible> xAccessible(aRelation.TargetSet[i], uno::UNO_QUERY); - relations->append( - { QAccessible::queryAccessibleInterface(new QtXAccessible(xAccessible)), aQRelation }); - } -} -} - -QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> -QtAccessibleWidget::relations(QAccessible::Relation match) const -{ - QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> relations; - - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return relations; - - Reference<XAccessibleRelationSet> xRelationSet = xAc->getAccessibleRelationSet(); - if (xRelationSet.is()) - { - if (match == QAccessible::AllRelations) - { - int count = xRelationSet->getRelationCount(); - for (int i = 0; i < count; i++) - { - AccessibleRelation aRelation = xRelationSet->getRelation(i); - lcl_appendRelation(&relations, aRelation); - } - } - else - { - AccessibleRelation aRelation = xRelationSet->getRelation(lcl_matchQtRelation(match)); - lcl_appendRelation(&relations, aRelation); - } - } - - return relations; -} - -QAccessibleInterface* QtAccessibleWidget::focusChild() const -{ - /* if (m_pWindow->HasChildPathFocus()) - return QAccessible::queryAccessibleInterface( - new QtXAccessible(m_xAccessible->getAccessibleContext()->getAccessibleChild(index))); */ - return QAccessible::queryAccessibleInterface(object()); -} - -QRect QtAccessibleWidget::rect() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QRect(); - - Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); - awt::Point aPoint = xAccessibleComponent->getLocation(); - awt::Size aSize = xAccessibleComponent->getSize(); - - return QRect(aPoint.X, aPoint.Y, aSize.Width, aSize.Height); -} - -QAccessibleInterface* QtAccessibleWidget::parent() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return nullptr; - - return QAccessible::queryAccessibleInterface(new QtXAccessible(xAc->getAccessibleParent())); -} -QAccessibleInterface* QtAccessibleWidget::child(int index) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return nullptr; - - return QAccessible::queryAccessibleInterface(new QtXAccessible(xAc->getAccessibleChild(index))); -} - -QString QtAccessibleWidget::text(QAccessible::Text text) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QString(); - - switch (text) - { - case QAccessible::Name: - return toQString(xAc->getAccessibleName()); - case QAccessible::Description: - case QAccessible::DebugDescription: - return toQString(xAc->getAccessibleDescription()); - case QAccessible::Value: - case QAccessible::Help: - case QAccessible::Accelerator: - case QAccessible::UserText: - default: - return QString("Unknown"); - } -} -QAccessible::Role QtAccessibleWidget::role() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QAccessible::NoRole; - - switch (xAc->getAccessibleRole()) - { - case AccessibleRole::UNKNOWN: - return QAccessible::NoRole; - - case AccessibleRole::ALERT: - return QAccessible::AlertMessage; - - case AccessibleRole::COLUMN_HEADER: - return QAccessible::ColumnHeader; - - case AccessibleRole::CANVAS: - return QAccessible::Canvas; - - case AccessibleRole::CHECK_BOX: - return QAccessible::CheckBox; - - case AccessibleRole::CHECK_MENU_ITEM: - return QAccessible::MenuItem; - - case AccessibleRole::COLOR_CHOOSER: - return QAccessible::ColorChooser; - - case AccessibleRole::COMBO_BOX: - return QAccessible::ComboBox; - - case AccessibleRole::DATE_EDITOR: - return QAccessible::EditableText; - - case AccessibleRole::DESKTOP_ICON: - return QAccessible::Graphic; - - case AccessibleRole::DESKTOP_PANE: - case AccessibleRole::DIRECTORY_PANE: - return QAccessible::Pane; - - case AccessibleRole::DIALOG: - return QAccessible::Dialog; - - case AccessibleRole::DOCUMENT: - return QAccessible::Document; - - case AccessibleRole::EMBEDDED_OBJECT: - return QAccessible::UserRole; - - case AccessibleRole::END_NOTE: - return QAccessible::Note; - - case AccessibleRole::FILLER: - return QAccessible::Whitespace; - - case AccessibleRole::FONT_CHOOSER: - return QAccessible::UserRole; - - case AccessibleRole::FOOTER: - return QAccessible::Footer; - - case AccessibleRole::FOOTNOTE: - return QAccessible::Note; - - case AccessibleRole::FRAME: // top-level window with title bar - return QAccessible::Window; - - case AccessibleRole::GLASS_PANE: - return QAccessible::UserRole; - - case AccessibleRole::GRAPHIC: - return QAccessible::Graphic; - - case AccessibleRole::GROUP_BOX: - return QAccessible::Grouping; - - case AccessibleRole::HEADER: - return QAccessible::UserRole; - - case AccessibleRole::HEADING: - return QAccessible::Heading; - - case AccessibleRole::HYPER_LINK: - return QAccessible::Link; - - case AccessibleRole::ICON: - return QAccessible::Graphic; - - case AccessibleRole::INTERNAL_FRAME: - return QAccessible::UserRole; - - case AccessibleRole::LABEL: - return QAccessible::StaticText; - - case AccessibleRole::LAYERED_PANE: - return QAccessible::Pane; - - case AccessibleRole::LIST: - return QAccessible::List; - - case AccessibleRole::LIST_ITEM: - return QAccessible::ListItem; - - case AccessibleRole::MENU: - case AccessibleRole::MENU_BAR: - return QAccessible::MenuBar; - - case AccessibleRole::MENU_ITEM: - return QAccessible::MenuItem; - - case AccessibleRole::OPTION_PANE: - return QAccessible::Pane; - - case AccessibleRole::PAGE_TAB: - return QAccessible::PageTab; - - case AccessibleRole::PAGE_TAB_LIST: - return QAccessible::PageTabList; - - case AccessibleRole::PANEL: - return QAccessible::Pane; - - case AccessibleRole::PARAGRAPH: - return QAccessible::Paragraph; - - case AccessibleRole::PASSWORD_TEXT: - return QAccessible::EditableText; - - case AccessibleRole::POPUP_MENU: - return QAccessible::PopupMenu; - - case AccessibleRole::PUSH_BUTTON: - return QAccessible::Button; - - case AccessibleRole::PROGRESS_BAR: - return QAccessible::ProgressBar; - - case AccessibleRole::RADIO_BUTTON: - return QAccessible::RadioButton; - - case AccessibleRole::RADIO_MENU_ITEM: - return QAccessible::MenuItem; - - case AccessibleRole::ROW_HEADER: - return QAccessible::RowHeader; - - case AccessibleRole::ROOT_PANE: - return QAccessible::Pane; - - case AccessibleRole::SCROLL_BAR: - return QAccessible::ScrollBar; - - case AccessibleRole::SCROLL_PANE: - return QAccessible::Pane; - - case AccessibleRole::SHAPE: - return QAccessible::Graphic; - - case AccessibleRole::SEPARATOR: - return QAccessible::Separator; - - case AccessibleRole::SLIDER: - return QAccessible::Slider; - - case AccessibleRole::SPIN_BOX: - return QAccessible::SpinBox; - - case AccessibleRole::SPLIT_PANE: - return QAccessible::Pane; - - case AccessibleRole::STATUS_BAR: - return QAccessible::StatusBar; - - case AccessibleRole::TABLE: - return QAccessible::Table; - - case AccessibleRole::TABLE_CELL: - return QAccessible::Cell; - - case AccessibleRole::TEXT: - return QAccessible::EditableText; - - case AccessibleRole::TEXT_FRAME: - return QAccessible::UserRole; - - case AccessibleRole::TOGGLE_BUTTON: - return QAccessible::Button; - - case AccessibleRole::TOOL_BAR: - return QAccessible::ToolBar; - - case AccessibleRole::TOOL_TIP: - return QAccessible::ToolTip; - - case AccessibleRole::TREE: - return QAccessible::Tree; - - case AccessibleRole::VIEW_PORT: - return QAccessible::UserRole; - - case AccessibleRole::BUTTON_DROPDOWN: - return QAccessible::Button; - - case AccessibleRole::BUTTON_MENU: - return QAccessible::Button; - - case AccessibleRole::CAPTION: - return QAccessible::StaticText; - - case AccessibleRole::CHART: - return QAccessible::Chart; - - case AccessibleRole::EDIT_BAR: - return QAccessible::Equation; - - case AccessibleRole::FORM: - return QAccessible::Form; - - case AccessibleRole::IMAGE_MAP: - return QAccessible::Graphic; - - case AccessibleRole::NOTE: - return QAccessible::Note; - - case AccessibleRole::RULER: - return QAccessible::UserRole; - - case AccessibleRole::SECTION: - return QAccessible::Section; - - case AccessibleRole::TREE_ITEM: - return QAccessible::TreeItem; - - case AccessibleRole::TREE_TABLE: - return QAccessible::Tree; - - case AccessibleRole::COMMENT: - return QAccessible::Note; - - case AccessibleRole::COMMENT_END: - return QAccessible::UserRole; - - case AccessibleRole::DOCUMENT_PRESENTATION: - return QAccessible::Document; - - case AccessibleRole::DOCUMENT_SPREADSHEET: - return QAccessible::Document; - - case AccessibleRole::DOCUMENT_TEXT: - return QAccessible::Document; - - case AccessibleRole::STATIC: - return QAccessible::StaticText; - - /* Ignore window objects for sub-menus, combo- and list boxes, - * which are exposed as children of their parents. - */ - case AccessibleRole::WINDOW: // top-level window without title bar - { - return QAccessible::Window; - } - } - - SAL_WARN("vcl.qt5", "Unmapped role: " << getAccessibleContextImpl()->getAccessibleRole()); - return QAccessible::NoRole; -} - -namespace -{ -void lcl_addState(QAccessible::State* state, sal_Int16 nState) -{ - switch (nState) - { - case AccessibleStateType::INVALID: - state->invalid = true; - break; - case AccessibleStateType::ACTIVE: - state->active = true; - break; - case AccessibleStateType::ARMED: - // No match - break; - case AccessibleStateType::BUSY: - state->busy = true; - break; - case AccessibleStateType::CHECKED: - state->checked = true; - break; - case AccessibleStateType::EDITABLE: - state->editable = true; - break; - case AccessibleStateType::ENABLED: - state->disabled = false; - break; - case AccessibleStateType::EXPANDABLE: - state->expandable = true; - break; - case AccessibleStateType::EXPANDED: - state->expanded = true; - break; - case AccessibleStateType::FOCUSABLE: - state->focusable = true; - break; - case AccessibleStateType::FOCUSED: - state->focused = true; - break; - case AccessibleStateType::HORIZONTAL: - // No match - break; - case AccessibleStateType::ICONIFIED: - // No match - break; - case AccessibleStateType::INDETERMINATE: - // No match - break; - case AccessibleStateType::MANAGES_DESCENDANTS: - // No match - break; - case AccessibleStateType::MODAL: - state->modal = true; - break; - case AccessibleStateType::MOVEABLE: - state->movable = true; - break; - case AccessibleStateType::MULTI_LINE: - state->multiLine = true; - break; - case AccessibleStateType::OPAQUE: - // No match - break; - case AccessibleStateType::PRESSED: - state->pressed = true; - break; - case AccessibleStateType::RESIZABLE: - state->sizeable = true; - break; - case AccessibleStateType::SELECTABLE: - state->selectable = true; - break; - case AccessibleStateType::SELECTED: - state->selected = true; - break; - case AccessibleStateType::SENSITIVE: - // No match - break; - case AccessibleStateType::SHOWING: - // No match - break; - case AccessibleStateType::SINGLE_LINE: - // No match - break; - case AccessibleStateType::STALE: - // No match - break; - case AccessibleStateType::TRANSIENT: - // No match - break; - case AccessibleStateType::VERTICAL: - // No match - break; - case AccessibleStateType::VISIBLE: - state->invisible = false; - break; - case AccessibleStateType::DEFAULT: - // No match - break; - case AccessibleStateType::DEFUNC: - state->invalid = true; - break; - case AccessibleStateType::MULTI_SELECTABLE: - state->multiSelectable = true; - break; - default: - SAL_WARN("vcl.qt5", "Unmapped state: " << nState); - break; - } -} -} - -QAccessible::State QtAccessibleWidget::state() const -{ - QAccessible::State state; - - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return state; - - Reference<XAccessibleStateSet> xStateSet(xAc->getAccessibleStateSet()); - - if (!xStateSet.is()) - return state; - - Sequence<sal_Int16> aStates = xStateSet->getStates(); - - for (const sal_Int16 nState : aStates) - { - lcl_addState(&state, nState); - } - - return state; -} - -QColor QtAccessibleWidget::foregroundColor() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QColor(); - - Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); - return toQColor(Color(ColorTransparency, xAccessibleComponent->getForeground())); -} - -QColor QtAccessibleWidget::backgroundColor() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QColor(); - - Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); - return toQColor(Color(ColorTransparency, xAccessibleComponent->getBackground())); -} - -void* QtAccessibleWidget::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::ActionInterface) - return static_cast<QAccessibleActionInterface*>(this); - if (t == QAccessible::TextInterface) - return static_cast<QAccessibleTextInterface*>(this); - if (t == QAccessible::EditableTextInterface) - return static_cast<QAccessibleEditableTextInterface*>(this); - if (t == QAccessible::ValueInterface) - return static_cast<QAccessibleValueInterface*>(this); - if (t == QAccessible::TableCellInterface) - return static_cast<QAccessibleTableCellInterface*>(this); - if (t == QAccessible::TableInterface) - return static_cast<QAccessibleTableInterface*>(this); - return nullptr; -} - -bool QtAccessibleWidget::isValid() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - return xAc.is(); -} - -QObject* QtAccessibleWidget::object() const { return m_pObject; } - -void QtAccessibleWidget::setText(QAccessible::Text /* t */, const QString& /* text */) {} - -QAccessibleInterface* QtAccessibleWidget::childAt(int x, int y) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return nullptr; - - Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); - return QAccessible::queryAccessibleInterface( - new QtXAccessible(xAccessibleComponent->getAccessibleAtPoint(awt::Point(x, y)))); -} - -QAccessibleInterface* QtAccessibleWidget::customFactory(const QString& classname, QObject* object) -{ - if (classname == QLatin1String("QtWidget") && object && object->isWidgetType()) - { - QtWidget* pWidget = static_cast<QtWidget*>(object); - vcl::Window* pWindow = pWidget->frame().GetWindow(); - - if (pWindow) - return new QtAccessibleWidget(pWindow->GetAccessible(), object); - } - if (classname == QLatin1String("QtXAccessible") && object) - { - QtXAccessible* pXAccessible = dynamic_cast<QtXAccessible*>(object); - if (pXAccessible && pXAccessible->m_xAccessible.is()) - return new QtAccessibleWidget(pXAccessible->m_xAccessible, object); - } - - return nullptr; -} - -// QAccessibleActionInterface -QStringList QtAccessibleWidget::actionNames() const -{ - QStringList actionNames; - Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY); - if (!xAccessibleAction.is()) - return actionNames; - - int count = xAccessibleAction->getAccessibleActionCount(); - for (int i = 0; i < count; i++) - { - OUString desc = xAccessibleAction->getAccessibleActionDescription(i); - actionNames.append(toQString(desc)); - } - return actionNames; -} - -void QtAccessibleWidget::doAction(const QString& actionName) -{ - Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY); - if (!xAccessibleAction.is()) - return; - - int index = actionNames().indexOf(actionName); - if (index == -1) - return; - xAccessibleAction->doAccessibleAction(index); -} - -QStringList QtAccessibleWidget::keyBindingsForAction(const QString& actionName) const -{ - QStringList keyBindings; - Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY); - if (!xAccessibleAction.is()) - return keyBindings; - - int index = actionNames().indexOf(actionName); - if (index == -1) - return keyBindings; - - Reference<XAccessibleKeyBinding> xKeyBinding - = xAccessibleAction->getAccessibleActionKeyBinding(index); - - if (!xKeyBinding.is()) - return keyBindings; - - int count = xKeyBinding->getAccessibleKeyBindingCount(); - for (int i = 0; i < count; i++) - { - Sequence<awt::KeyStroke> keyStroke = xKeyBinding->getAccessibleKeyBinding(i); - keyBindings.append(toQString(comphelper::GetkeyBindingStrByXkeyBinding(keyStroke))); - } - return keyBindings; -} - -// QAccessibleTextInterface -void QtAccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */) -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::addSelection"); -} - -namespace -{ -OUString lcl_convertFontWeight(double fontWeight) -{ - if (fontWeight == awt::FontWeight::THIN || fontWeight == awt::FontWeight::ULTRALIGHT) - return "100"; - if (fontWeight == awt::FontWeight::LIGHT) - return "200"; - if (fontWeight == awt::FontWeight::SEMILIGHT) - return "300"; - if (fontWeight == awt::FontWeight::NORMAL) - return "normal"; - if (fontWeight == awt::FontWeight::SEMIBOLD) - return "500"; - if (fontWeight == awt::FontWeight::BOLD) - return "bold"; - if (fontWeight == awt::FontWeight::ULTRABOLD) - return "800"; - if (fontWeight == awt::FontWeight::BLACK) - return "900"; - - // awt::FontWeight::DONTKNOW || fontWeight == awt::FontWeight::NORMAL - return "normal"; -} -} - -QString QtAccessibleWidget::attributes(int offset, int* startOffset, int* endOffset) const -{ - if (startOffset == nullptr || endOffset == nullptr) - return QString(); - - *startOffset = -1; - *endOffset = -1; - - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (!xText.is()) - return QString(); - - // handle special values for offset the same way base class's QAccessibleTextWidget::attributes does - // (as defined in IAccessible 2: -1 -> length, -2 -> cursor position) - if (offset == -2) - offset = cursorPosition(); - - const int nTextLength = characterCount(); - if (offset == -1 || offset == nTextLength) - offset = nTextLength - 1; - - if (offset < 0 || offset > nTextLength) - return QString(); - - const Sequence<PropertyValue> attribs - = xText->getCharacterAttributes(offset, Sequence<OUString>()); - OUString aRet; - for (PropertyValue const& prop : attribs) - { - OUString sAttribute; - OUString sValue; - if (prop.Name == "CharFontName") - { - sAttribute = "font-family"; - sValue = *o3tl::doAccess<OUString>(prop.Value); - } - else if (prop.Name == "CharHeight") - { - sAttribute = "font-size"; - sValue = OUString::number(*o3tl::doAccess<double>(prop.Value)) + "pt"; - } - else if (prop.Name == "CharWeight") - { - sAttribute = "font-weight"; - sValue = lcl_convertFontWeight(*o3tl::doAccess<double>(prop.Value)); - } - - if (!sAttribute.isEmpty() && !sValue.isEmpty()) - aRet += sAttribute + ":" + sValue + ";"; - } - *startOffset = offset; - *endOffset = offset + 1; - return toQString(aRet); -} - -int QtAccessibleWidget::characterCount() const -{ - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - return xText->getCharacterCount(); - return 0; -} -QRect QtAccessibleWidget::characterRect(int /* offset */) const -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::characterRect"); - return QRect(); -} - -int QtAccessibleWidget::cursorPosition() const -{ - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - return xText->getCaretPosition(); - return 0; -} - -int QtAccessibleWidget::offsetAtPoint(const QPoint& /* point */) const -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::offsetAtPoint"); - return 0; -} -void QtAccessibleWidget::removeSelection(int /* selectionIndex */) -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::removeSelection"); -} -void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex) -{ - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE); -} - -void QtAccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const -{ - if (!startOffset && !endOffset) - return; - - Reference<XAccessibleText> xText; - if (selectionIndex == 0) - xText = Reference<XAccessibleText>(getAccessibleContextImpl(), UNO_QUERY); - - if (startOffset) - *startOffset = xText.is() ? xText->getSelectionStart() : 0; - if (endOffset) - *endOffset = xText.is() ? xText->getSelectionEnd() : 0; -} - -int QtAccessibleWidget::selectionCount() const -{ - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is() && !xText->getSelectedText().isEmpty()) - return 1; // Only 1 selection supported atm - return 0; -} -void QtAccessibleWidget::setCursorPosition(int position) -{ - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - xText->setCaretPosition(position); -} -void QtAccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset) -{ - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - xText->setSelection(startOffset, endOffset); -} -QString QtAccessibleWidget::text(int startOffset, int endOffset) const -{ - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - return toQString(xText->getTextRange(startOffset, endOffset)); - return QString(); -} -QString QtAccessibleWidget::textAfterOffset(int /* offset */, - QAccessible::TextBoundaryType /* boundaryType */, - int* /* startOffset */, int* /* endOffset */) const -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textAfterOffset"); - return QString(); -} - -QString QtAccessibleWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int* startOffset, int* endOffset) const -{ - if (startOffset == nullptr || endOffset == nullptr) - return QString(); - - if (boundaryType == QAccessible::NoBoundary) - { - const int nCharCount = characterCount(); - *startOffset = 0; - *endOffset = nCharCount; - return text(0, nCharCount); - } - - Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (!xText.is()) - return QString(); - - sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(boundaryType); - assert(nUnoBoundaryType > 0); - - const TextSegment segment = xText->getTextAtIndex(offset, nUnoBoundaryType); - *startOffset = segment.SegmentStart; - *endOffset = segment.SegmentEnd; - return toQString(segment.SegmentText); -} - -QString QtAccessibleWidget::textBeforeOffset(int /* offset */, - QAccessible::TextBoundaryType /* boundaryType */, - int* /* startOffset */, int* /* endOffset */) const -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textBeforeOffset"); - return QString(); -} - -// QAccessibleEditableTextInterface - -void QtAccessibleWidget::deleteText(int startOffset, int endOffset) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return; - - Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); - if (!xEditableText.is()) - return; - xEditableText->deleteText(startOffset, endOffset); -} - -void QtAccessibleWidget::insertText(int offset, const QString& text) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return; - - Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); - if (!xEditableText.is()) - return; - xEditableText->insertText(toOUString(text), offset); -} - -void QtAccessibleWidget::replaceText(int startOffset, int endOffset, const QString& text) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return; - - Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); - if (!xEditableText.is()) - return; - xEditableText->replaceText(startOffset, endOffset, toOUString(text)); -} - -// QAccessibleValueInterface -QVariant QtAccessibleWidget::currentValue() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QVariant(); - - Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); - if (!xValue.is()) - return QVariant(); - double aDouble = 0; - xValue->getCurrentValue() >>= aDouble; - return QVariant(aDouble); -} - -QVariant QtAccessibleWidget::maximumValue() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QVariant(); - - Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); - if (!xValue.is()) - return QVariant(); - double aDouble = 0; - xValue->getMaximumValue() >>= aDouble; - return QVariant(aDouble); -} - -QVariant QtAccessibleWidget::minimumStepSize() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QVariant(); - - Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); - if (!xValue.is()) - return QVariant(); - double dMinStep = 0; - xValue->getMinimumIncrement() >>= dMinStep; - return QVariant(dMinStep); -} - -QVariant QtAccessibleWidget::minimumValue() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QVariant(); - - Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); - if (!xValue.is()) - return QVariant(); - double aDouble = 0; - xValue->getMinimumValue() >>= aDouble; - return QVariant(aDouble); -} - -void QtAccessibleWidget::setCurrentValue(const QVariant& value) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return; - - Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); - if (!xValue.is()) - return; - xValue->setCurrentValue(Any(value.toDouble())); -} - -// QAccessibleTable -QAccessibleInterface* QtAccessibleWidget::caption() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return nullptr; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return nullptr; - return QAccessible::queryAccessibleInterface(new QtXAccessible(xTable->getAccessibleCaption())); -} - -QAccessibleInterface* QtAccessibleWidget::cellAt(int row, int column) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return nullptr; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return nullptr; - return QAccessible::queryAccessibleInterface( - new QtXAccessible(xTable->getAccessibleCellAt(row, column))); -} - -int QtAccessibleWidget::columnCount() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return 0; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return 0; - return xTable->getAccessibleColumnCount(); -} - -QString QtAccessibleWidget::columnDescription(int column) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QString(); - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return QString(); - return toQString(xTable->getAccessibleColumnDescription(column)); -} - -bool QtAccessibleWidget::isColumnSelected(int nColumn) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return false; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return false; - - return xTable->isAccessibleColumnSelected(nColumn); -} - -bool QtAccessibleWidget::isRowSelected(int nRow) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return false; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return false; - - return xTable->isAccessibleRowSelected(nRow); -} - -void QtAccessibleWidget::modelChange(QAccessibleTableModelChangeEvent*) {} - -int QtAccessibleWidget::rowCount() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return 0; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return 0; - return xTable->getAccessibleRowCount(); -} - -QString QtAccessibleWidget::rowDescription(int row) const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QString(); - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return QString(); - return toQString(xTable->getAccessibleRowDescription(row)); -} - -bool QtAccessibleWidget::selectColumn(int column) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return false; - - Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); - if (!xTableSelection.is()) - return false; - return xTableSelection->selectColumn(column); -} - -bool QtAccessibleWidget::selectRow(int row) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return false; - - Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); - if (!xTableSelection.is()) - return false; - return xTableSelection->selectRow(row); -} - -int QtAccessibleWidget::selectedCellCount() const -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCellCount"); - return 0; -} - -QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const -{ - SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCells"); - return QList<QAccessibleInterface*>(); -} - -int QtAccessibleWidget::selectedColumnCount() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return 0; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return 0; - return xTable->getSelectedAccessibleColumns().getLength(); -} - -QList<int> QtAccessibleWidget::selectedColumns() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QList<int>(); - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return QList<int>(); - return toQList(xTable->getSelectedAccessibleColumns()); -} - -int QtAccessibleWidget::selectedRowCount() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return 0; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return 0; - return xTable->getSelectedAccessibleRows().getLength(); -} - -QList<int> QtAccessibleWidget::selectedRows() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return QList<int>(); - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return QList<int>(); - return toQList(xTable->getSelectedAccessibleRows()); -} - -QAccessibleInterface* QtAccessibleWidget::summary() const -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return nullptr; - - Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); - if (!xTable.is()) - return nullptr; - return QAccessible::queryAccessibleInterface(new QtXAccessible(xTable->getAccessibleSummary())); -} - -bool QtAccessibleWidget::unselectColumn(int column) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return false; - - Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); - if (!xTableSelection.is()) - return false; - return xTableSelection->unselectColumn(column); -} - -bool QtAccessibleWidget::unselectRow(int row) -{ - Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); - if (!xAc.is()) - return false; - - Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); - if (!xTableSelection.is()) - return false; - return xTableSelection->unselectRow(row); -} - -QList<QAccessibleInterface*> QtAccessibleWidget::columnHeaderCells() const -{ - SAL_WARN("vcl.qt5", "Unsupported QAccessibleTableCellInterface::columnHeaderCells"); - return QList<QAccessibleInterface*>(); -} - -int QtAccessibleWidget::columnIndex() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return -1; - - Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); - if (!xTable.is()) - return -1; - - const sal_Int32 nIndexInParent = xAcc->getAccessibleIndexInParent(); - return xTable->getAccessibleColumn(nIndexInParent); -} - -bool QtAccessibleWidget::isSelected() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return false; - - Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); - if (!xTable.is()) - return false; - - const sal_Int32 nColumn = columnIndex(); - const sal_Int32 nRow = rowIndex(); - return xTable->isAccessibleSelected(nRow, nColumn); -} - -int QtAccessibleWidget::columnExtent() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return -1; - - Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); - if (!xTable.is()) - return -1; - - const sal_Int32 nColumn = columnIndex(); - const sal_Int32 nRow = rowIndex(); - return xTable->getAccessibleColumnExtentAt(nRow, nColumn); -} - -QList<QAccessibleInterface*> QtAccessibleWidget::rowHeaderCells() const -{ - SAL_WARN("vcl.qt5", "Unsupported QAccessibleTableCellInterface::rowHeaderCells"); - return QList<QAccessibleInterface*>(); -} - -int QtAccessibleWidget::rowExtent() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return -1; - - Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); - if (!xTable.is()) - return -1; - - const sal_Int32 nColumn = columnIndex(); - const sal_Int32 nRow = rowIndex(); - return xTable->getAccessibleRowExtentAt(nRow, nColumn); -} - -int QtAccessibleWidget::rowIndex() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return -1; - - Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); - if (!xTable.is()) - return -1; - - const sal_Int32 nIndexInParent = xAcc->getAccessibleIndexInParent(); - return xTable->getAccessibleRow(nIndexInParent); -} - -QAccessibleInterface* QtAccessibleWidget::table() const -{ - SAL_WARN("vcl.qt5", "Unsupported QAccessibleTableCellInterface::table"); - return nullptr; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Bitmap.cxx b/vcl/qt5/Qt5Bitmap.cxx deleted file mode 100644 index 951046612e46..000000000000 --- a/vcl/qt5/Qt5Bitmap.cxx +++ /dev/null @@ -1,188 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Bitmap.hxx> -#include <Qt5Tools.hxx> -#include <Qt5Graphics.hxx> - -#include <QtGui/QImage> -#include <QtCore/QVector> -#include <QtGui/QColor> - -#include <o3tl/safeint.hxx> -#include <sal/log.hxx> -#include <tools/helpers.hxx> - -QtBitmap::QtBitmap() {} - -QtBitmap::QtBitmap(const QImage& rImage) { m_pImage.reset(new QImage(rImage)); } - -bool QtBitmap::Create(const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal) -{ - if (ePixelFormat == vcl::PixelFormat::INVALID) - return false; - - if (ePixelFormat == vcl::PixelFormat::N1_BPP) - assert(2 >= rPal.GetEntryCount()); - if (ePixelFormat == vcl::PixelFormat::N8_BPP) - assert(256 >= rPal.GetEntryCount()); - - m_pImage.reset(new QImage(toQSize(rSize), getBitFormat(ePixelFormat))); - m_pImage->fill(Qt::transparent); - m_aPalette = rPal; - - auto count = rPal.GetEntryCount(); - if (count && m_pImage) - { - QVector<QRgb> aColorTable(count); - for (unsigned i = 0; i < count; ++i) - aColorTable[i] = qRgb(rPal[i].GetRed(), rPal[i].GetGreen(), rPal[i].GetBlue()); - m_pImage->setColorTable(aColorTable); - } - return true; -} - -bool QtBitmap::Create(const SalBitmap& rSalBmp) -{ - const QtBitmap* pBitmap = static_cast<const QtBitmap*>(&rSalBmp); - m_pImage.reset(new QImage(*pBitmap->m_pImage)); - m_aPalette = pBitmap->m_aPalette; - return true; -} - -bool QtBitmap::Create(const SalBitmap& rSalBmp, SalGraphics* pSalGraphics) -{ - const QtBitmap* pBitmap = static_cast<const QtBitmap*>(&rSalBmp); - QtGraphics* pGraphics = static_cast<QtGraphics*>(pSalGraphics); - QImage* pImage = pGraphics->getQImage(); - m_pImage.reset(new QImage(pBitmap->m_pImage->convertToFormat(pImage->format()))); - return true; -} - -bool QtBitmap::Create(const SalBitmap& rSalBmp, vcl::PixelFormat eNewPixelFormat) -{ - if (eNewPixelFormat == vcl::PixelFormat::INVALID) - return false; - const QtBitmap* pBitmap = static_cast<const QtBitmap*>(&rSalBmp); - m_pImage.reset(new QImage(pBitmap->m_pImage->convertToFormat(getBitFormat(eNewPixelFormat)))); - return true; -} - -bool QtBitmap::Create(const css::uno::Reference<css::rendering::XBitmapCanvas>& /*rBitmapCanvas*/, - Size& /*rSize*/, bool /*bMask*/) -{ - return false; -} - -void QtBitmap::Destroy() { m_pImage.reset(); } - -Size QtBitmap::GetSize() const -{ - if (m_pImage) - return toSize(m_pImage->size()); - return Size(); -} - -sal_uInt16 QtBitmap::GetBitCount() const -{ - if (m_pImage) - return getFormatBits(m_pImage->format()); - return 0; -} - -BitmapBuffer* QtBitmap::AcquireBuffer(BitmapAccessMode /*nMode*/) -{ - static const BitmapPalette aEmptyPalette; - - if (!m_pImage) - return nullptr; - - BitmapBuffer* pBuffer = new BitmapBuffer; - - pBuffer->mnWidth = m_pImage->width(); - pBuffer->mnHeight = m_pImage->height(); - pBuffer->mnBitCount = getFormatBits(m_pImage->format()); - pBuffer->mpBits = m_pImage->bits(); - pBuffer->mnScanlineSize = m_pImage->bytesPerLine(); - - switch (pBuffer->mnBitCount) - { - case 1: - pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal | ScanlineFormat::TopDown; - pBuffer->maPalette = m_aPalette; - break; - case 8: - pBuffer->mnFormat = ScanlineFormat::N8BitPal | ScanlineFormat::TopDown; - pBuffer->maPalette = m_aPalette; - break; - case 24: - pBuffer->mnFormat = ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown; - pBuffer->maPalette = aEmptyPalette; - break; - case 32: - { -#ifdef OSL_BIGENDIAN - pBuffer->mnFormat = ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown; -#else - pBuffer->mnFormat = ScanlineFormat::N32BitTcBgra | ScanlineFormat::TopDown; -#endif - pBuffer->maPalette = aEmptyPalette; - break; - } - default: - assert(false); - } - - return pBuffer; -} - -void QtBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) -{ - m_aPalette = pBuffer->maPalette; - auto count = m_aPalette.GetEntryCount(); - if (pBuffer->mnBitCount != 4 && count) - { - QVector<QRgb> aColorTable(count); - for (unsigned i = 0; i < count; ++i) - aColorTable[i] - = qRgb(m_aPalette[i].GetRed(), m_aPalette[i].GetGreen(), m_aPalette[i].GetBlue()); - m_pImage->setColorTable(aColorTable); - } - delete pBuffer; - if (nMode == BitmapAccessMode::Write) - InvalidateChecksum(); -} - -bool QtBitmap::GetSystemData(BitmapSystemData& /*rData*/) { return false; } - -bool QtBitmap::ScalingSupported() const { return false; } - -bool QtBitmap::Scale(const double& /*rScaleX*/, const double& /*rScaleY*/, - BmpScaleFlag /*nScaleFlag*/) -{ - return false; -} - -bool QtBitmap::Replace(const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, - sal_uInt8 /*nTol*/) -{ - return false; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Clipboard.cxx b/vcl/qt5/Qt5Clipboard.cxx deleted file mode 100644 index 6ab93258bf09..000000000000 --- a/vcl/qt5/Qt5Clipboard.cxx +++ /dev/null @@ -1,252 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <Qt5Clipboard.hxx> -#include <Qt5Clipboard.moc> - -#include <cppuhelper/supportsservice.hxx> -#include <sal/log.hxx> - -#include <QtWidgets/QApplication> - -#include <Qt5Instance.hxx> -#include <Qt5Transferable.hxx> -#include <Qt5Tools.hxx> - -#include <cassert> -#include <map> - -QtClipboard::QtClipboard(const OUString& aModeString, const QClipboard::Mode aMode) - : cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard, - css::datatransfer::clipboard::XFlushableClipboard, - XServiceInfo>(m_aMutex) - , m_aClipboardName(aModeString) - , m_aClipboardMode(aMode) - , m_bOwnClipboardChange(false) - , m_bDoClear(false) -{ - assert(isSupported(m_aClipboardMode)); - // DirectConnection guarantees the changed slot runs in the same thread as the QClipboard - connect(QApplication::clipboard(), &QClipboard::changed, this, &QtClipboard::handleChanged, - Qt::DirectConnection); - - // explicitly queue an event, so we can eventually ignore it - connect(this, &QtClipboard::clearClipboard, this, &QtClipboard::handleClearClipboard, - Qt::QueuedConnection); -} - -css::uno::Reference<css::uno::XInterface> QtClipboard::create(const OUString& aModeString) -{ - static const std::map<OUString, QClipboard::Mode> aNameToClipboardMap - = { { "CLIPBOARD", QClipboard::Clipboard }, { "PRIMARY", QClipboard::Selection } }; - - assert(QApplication::clipboard()->thread() == qApp->thread()); - - auto iter = aNameToClipboardMap.find(aModeString); - if (iter != aNameToClipboardMap.end() && isSupported(iter->second)) - return static_cast<cppu::OWeakObject*>(new QtClipboard(aModeString, iter->second)); - SAL_WARN("vcl.qt5", "Ignoring unrecognized clipboard type: '" << aModeString << "'"); - return css::uno::Reference<css::uno::XInterface>(); -} - -void QtClipboard::flushClipboard() -{ - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - SolarMutexGuard g; - pSalInst->RunInMainThread([this]() { - if (!isOwner(m_aClipboardMode)) - return; - - QClipboard* pClipboard = QApplication::clipboard(); - const QtMimeData* pQtMimeData - = dynamic_cast<const QtMimeData*>(pClipboard->mimeData(m_aClipboardMode)); - assert(pQtMimeData); - - QMimeData* pMimeCopy = nullptr; - if (pQtMimeData && pQtMimeData->deepCopy(&pMimeCopy)) - { - m_bOwnClipboardChange = true; - pClipboard->setMimeData(pMimeCopy, m_aClipboardMode); - m_bOwnClipboardChange = false; - } - }); -} - -css::uno::Reference<css::datatransfer::XTransferable> QtClipboard::getContents() -{ - osl::MutexGuard aGuard(m_aMutex); - - // if we're the owner, we might have the XTransferable from setContents. but - // maybe a non-LO clipboard change from within LO, like some C'n'P in the - // QFileDialog, might have invalidated m_aContents, so we need to check it too. - if (isOwner(m_aClipboardMode) && m_aContents.is()) - return m_aContents; - - // check if we can still use the shared QtClipboardTransferable - const QMimeData* pMimeData = QApplication::clipboard()->mimeData(m_aClipboardMode); - if (m_aContents.is()) - { - const auto* pTrans = dynamic_cast<QtClipboardTransferable*>(m_aContents.get()); - assert(pTrans); - if (pTrans && pTrans->mimeData() == pMimeData) - return m_aContents; - } - - m_aContents = new QtClipboardTransferable(m_aClipboardMode, pMimeData); - return m_aContents; -} - -void QtClipboard::handleClearClipboard() -{ - if (!m_bDoClear) - return; - QApplication::clipboard()->clear(m_aClipboardMode); -} - -void QtClipboard::setContents( - const css::uno::Reference<css::datatransfer::XTransferable>& xTrans, - const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner) -{ - // it's actually possible to get a non-empty xTrans and an empty xClipboardOwner! - osl::ClearableMutexGuard aGuard(m_aMutex); - - css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner); - css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents); - m_aContents = xTrans; - m_aOwner = xClipboardOwner; - - m_bDoClear = !m_aContents.is(); - if (!m_bDoClear) - { - m_bOwnClipboardChange = true; - QApplication::clipboard()->setMimeData(new QtMimeData(m_aContents), m_aClipboardMode); - m_bOwnClipboardChange = false; - } - else - { - assert(!m_aOwner.is()); - Q_EMIT clearClipboard(); - } - - aGuard.clear(); - - // we have to notify only an owner change, since handleChanged can't - // access the previous owner anymore and can just handle lost ownership. - if (xOldOwner.is() && xOldOwner != xClipboardOwner) - xOldOwner->lostOwnership(this, xOldContents); -} - -void QtClipboard::handleChanged(QClipboard::Mode aMode) -{ - if (aMode != m_aClipboardMode) - return; - - osl::ClearableMutexGuard aGuard(m_aMutex); - - // QtWayland will send a second change notification (seemingly without any - // trigger). And any C'n'P operation in the Qt file picker emits a signal, - // with LO still holding the clipboard ownership, but internally having lost - // it. So ignore any signal, which still delivers the internal QtMimeData - // as the clipboard content and is no "advertised" change. - if (!m_bOwnClipboardChange && isOwner(aMode) - && dynamic_cast<const QtMimeData*>(QApplication::clipboard()->mimeData(aMode))) - return; - - css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner); - css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents); - // ownership change from LO POV is handled in setContents - if (!m_bOwnClipboardChange) - { - m_aContents.clear(); - m_aOwner.clear(); - } - - std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> aListeners( - m_aListeners); - css::datatransfer::clipboard::ClipboardEvent aEv; - aEv.Contents = getContents(); - - aGuard.clear(); - - if (!m_bOwnClipboardChange && xOldOwner.is()) - xOldOwner->lostOwnership(this, xOldContents); - for (auto const& listener : aListeners) - listener->changedContents(aEv); -} - -OUString QtClipboard::getImplementationName() { return "com.sun.star.datatransfer.QtClipboard"; } - -css::uno::Sequence<OUString> QtClipboard::getSupportedServiceNames() -{ - return { "com.sun.star.datatransfer.clipboard.SystemClipboard" }; -} - -sal_Bool QtClipboard::supportsService(const OUString& ServiceName) -{ - return cppu::supportsService(this, ServiceName); -} - -OUString QtClipboard::getName() { return m_aClipboardName; } - -sal_Int8 QtClipboard::getRenderingCapabilities() { return 0; } - -void QtClipboard::addClipboardListener( - const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) -{ - osl::MutexGuard aGuard(m_aMutex); - m_aListeners.push_back(listener); -} - -void QtClipboard::removeClipboardListener( - const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) -{ - osl::MutexGuard aGuard(m_aMutex); - m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener), - m_aListeners.end()); -} - -bool QtClipboard::isSupported(const QClipboard::Mode aMode) -{ - const QClipboard* pClipboard = QApplication::clipboard(); - switch (aMode) - { - case QClipboard::Selection: - return pClipboard->supportsSelection(); - - case QClipboard::FindBuffer: - return pClipboard->supportsFindBuffer(); - - case QClipboard::Clipboard: - return true; - } - return false; -} - -bool QtClipboard::isOwner(const QClipboard::Mode aMode) -{ - if (!isSupported(aMode)) - return false; - - const QClipboard* pClipboard = QApplication::clipboard(); - switch (aMode) - { - case QClipboard::Selection: - return pClipboard->ownsSelection(); - - case QClipboard::FindBuffer: - return pClipboard->ownsFindBuffer(); - - case QClipboard::Clipboard: - return pClipboard->ownsClipboard(); - } - return false; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Data.cxx b/vcl/qt5/Qt5Data.cxx deleted file mode 100644 index 0b4c9dad8b00..000000000000 --- a/vcl/qt5/Qt5Data.cxx +++ /dev/null @@ -1,337 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Data.hxx> - -#include <QtGui/QBitmap> -#include <QtGui/QCursor> -#include <QtWidgets/QApplication> -#include <QtWidgets/QStyle> - -#include <sal/log.hxx> - -#include <unx/x11_cursors/ase_curs.h> -#include <unx/x11_cursors/ase_mask.h> -#include <unx/x11_cursors/asn_curs.h> -#include <unx/x11_cursors/asn_mask.h> -#include <unx/x11_cursors/asne_curs.h> -#include <unx/x11_cursors/asne_mask.h> -#include <unx/x11_cursors/asns_curs.h> -#include <unx/x11_cursors/asns_mask.h> -#include <unx/x11_cursors/asnswe_curs.h> -#include <unx/x11_cursors/asnswe_mask.h> -#include <unx/x11_cursors/asnw_curs.h> -#include <unx/x11_cursors/asnw_mask.h> -#include <unx/x11_cursors/ass_curs.h> -#include <unx/x11_cursors/ass_mask.h> -#include <unx/x11_cursors/asse_curs.h> -#include <unx/x11_cursors/asse_mask.h> -#include <unx/x11_cursors/assw_curs.h> -#include <unx/x11_cursors/assw_mask.h> -#include <unx/x11_cursors/asw_curs.h> -#include <unx/x11_cursors/asw_mask.h> -#include <unx/x11_cursors/aswe_curs.h> -#include <unx/x11_cursors/aswe_mask.h> -#include <unx/x11_cursors/chain_curs.h> -#include <unx/x11_cursors/chain_mask.h> -#include <unx/x11_cursors/chainnot_curs.h> -#include <unx/x11_cursors/chainnot_mask.h> -#include <unx/x11_cursors/chart_curs.h> -#include <unx/x11_cursors/chart_mask.h> -#include <unx/x11_cursors/copydata_curs.h> -#include <unx/x11_cursors/copydata_mask.h> -#include <unx/x11_cursors/copydlnk_curs.h> -#include <unx/x11_cursors/copydlnk_mask.h> -#include <unx/x11_cursors/copyfile_curs.h> -#include <unx/x11_cursors/copyfile_mask.h> -#include <unx/x11_cursors/copyfiles_curs.h> -#include <unx/x11_cursors/copyfiles_mask.h> -#include <unx/x11_cursors/copyflnk_curs.h> -#include <unx/x11_cursors/copyflnk_mask.h> -#include <unx/x11_cursors/crook_curs.h> -#include <unx/x11_cursors/crook_mask.h> -#include <unx/x11_cursors/crop_curs.h> -#include <unx/x11_cursors/crop_mask.h> -#include <unx/x11_cursors/detective_curs.h> -#include <unx/x11_cursors/detective_mask.h> -#include <unx/x11_cursors/drawarc_curs.h> -#include <unx/x11_cursors/drawarc_mask.h> -#include <unx/x11_cursors/drawbezier_curs.h> -#include <unx/x11_cursors/drawbezier_mask.h> -#include <unx/x11_cursors/drawcaption_curs.h> -#include <unx/x11_cursors/drawcaption_mask.h> -#include <unx/x11_cursors/drawcirclecut_curs.h> -#include <unx/x11_cursors/drawcirclecut_mask.h> -#include <unx/x11_cursors/drawconnect_curs.h> -#include <unx/x11_cursors/drawconnect_mask.h> -#include <unx/x11_cursors/drawellipse_curs.h> -#include <unx/x11_cursors/drawellipse_mask.h> -#include <unx/x11_cursors/drawfreehand_curs.h> -#include <unx/x11_cursors/drawfreehand_mask.h> -#include <unx/x11_cursors/drawline_curs.h> -#include <unx/x11_cursors/drawline_mask.h> -#include <unx/x11_cursors/drawpie_curs.h> -#include <unx/x11_cursors/drawpie_mask.h> -#include <unx/x11_cursors/drawpolygon_curs.h> -#include <unx/x11_cursors/drawpolygon_mask.h> -#include <unx/x11_cursors/drawrect_curs.h> -#include <unx/x11_cursors/drawrect_mask.h> -#include <unx/x11_cursors/drawtext_curs.h> -#include <unx/x11_cursors/drawtext_mask.h> -#include <unx/x11_cursors/fill_curs.h> -#include <unx/x11_cursors/fill_mask.h> -#include <unx/x11_cursors/hshear_curs.h> -#include <unx/x11_cursors/hshear_mask.h> -#include <unx/x11_cursors/linkdata_curs.h> -#include <unx/x11_cursors/linkdata_mask.h> -#include <unx/x11_cursors/linkfile_curs.h> -#include <unx/x11_cursors/linkfile_mask.h> -#include <unx/x11_cursors/magnify_curs.h> -#include <unx/x11_cursors/magnify_mask.h> -#include <unx/x11_cursors/mirror_curs.h> -#include <unx/x11_cursors/mirror_mask.h> -#include <unx/x11_cursors/movebezierweight_curs.h> -#include <unx/x11_cursors/movebezierweight_mask.h> -#include <unx/x11_cursors/movedata_curs.h> -#include <unx/x11_cursors/movedata_mask.h> -#include <unx/x11_cursors/movedlnk_curs.h> -#include <unx/x11_cursors/movedlnk_mask.h> -#include <unx/x11_cursors/movefile_curs.h> -#include <unx/x11_cursors/movefile_mask.h> -#include <unx/x11_cursors/movefiles_curs.h> -#include <unx/x11_cursors/movefiles_mask.h> -#include <unx/x11_cursors/moveflnk_curs.h> -#include <unx/x11_cursors/moveflnk_mask.h> -#include <unx/x11_cursors/movepoint_curs.h> -#include <unx/x11_cursors/movepoint_mask.h> -#include <unx/x11_cursors/nodrop_curs.h> -#include <unx/x11_cursors/nodrop_mask.h> -#include <unx/x11_cursors/pivotcol_curs.h> -#include <unx/x11_cursors/pivotcol_mask.h> -#include <unx/x11_cursors/pivotdel_curs.h> -#include <unx/x11_cursors/pivotdel_mask.h> -#include <unx/x11_cursors/pivotfld_curs.h> -#include <unx/x11_cursors/pivotfld_mask.h> -#include <unx/x11_cursors/pivotrow_curs.h> -#include <unx/x11_cursors/pivotrow_mask.h> -#include <unx/x11_cursors/rotate_curs.h> -#include <unx/x11_cursors/rotate_mask.h> -#include <unx/x11_cursors/tblsele_curs.h> -#include <unx/x11_cursors/tblsele_mask.h> -#include <unx/x11_cursors/tblsels_curs.h> -#include <unx/x11_cursors/tblsels_mask.h> -#include <unx/x11_cursors/tblselse_curs.h> -#include <unx/x11_cursors/tblselse_mask.h> -#include <unx/x11_cursors/tblselsw_curs.h> -#include <unx/x11_cursors/tblselsw_mask.h> -#include <unx/x11_cursors/tblselw_curs.h> -#include <unx/x11_cursors/tblselw_mask.h> -#include <unx/x11_cursors/vertcurs_curs.h> -#include <unx/x11_cursors/vertcurs_mask.h> -#include <unx/x11_cursors/vshear_curs.h> -#include <unx/x11_cursors/vshear_mask.h> -#include <unx/x11_cursors/wshide_curs.h> -#include <unx/x11_cursors/wshide_mask.h> -#include <unx/x11_cursors/wsshow_curs.h> -#include <unx/x11_cursors/wsshow_mask.h> -#include <unx/x11_cursors/fatcross_curs.h> -#include <unx/x11_cursors/fatcross_mask.h> - -#include <unx/glyphcache.hxx> - -QtData::QtData(SalInstance* pInstance) - : GenericUnixSalData(pInstance) -{ - ImplSVData* pSVData = ImplGetSVData(); - - pSVData->maNWFData.mbDockingAreaSeparateTB = true; - pSVData->maNWFData.mbFlatMenu = true; - pSVData->maNWFData.mbRolloverMenubar = true; - pSVData->maNWFData.mbNoFocusRects = true; - pSVData->maNWFData.mbNoFocusRectsForFlatButtons = true; - - QStyle* style = QApplication::style(); - pSVData->maNWFData.mnMenuFormatBorderX = style->pixelMetric(QStyle::PM_MenuPanelWidth) - + style->pixelMetric(QStyle::PM_MenuHMargin); - pSVData->maNWFData.mnMenuFormatBorderY = style->pixelMetric(QStyle::PM_MenuPanelWidth) - + style->pixelMetric(QStyle::PM_MenuVMargin); -} - -// outline dtor b/c of FreetypeManager incomplete type -QtData::~QtData() {} - -static QCursor* getQCursorFromXBM(const unsigned char* pBitmap, const unsigned char* pMask, - int nWidth, int nHeight, int nXHot, int nYHot) -{ - QBitmap aPixmap = QBitmap::fromData(QSize(nWidth, nHeight), pBitmap); - QBitmap aMask = QBitmap::fromData(QSize(nWidth, nHeight), pMask); - return new QCursor(aPixmap, aMask, nXHot, nYHot); -} -#define MAKE_CURSOR(vcl_name, name) \ - case vcl_name: \ - pCursor = getQCursorFromXBM(name##curs##_bits, name##mask##_bits, name##curs_width, \ - name##curs_height, name##curs_x_hot, name##curs_y_hot); \ - break - -#define MAP_BUILTIN(vcl_name, qt_enum) \ - case vcl_name: \ - pCursor = new QCursor(qt_enum); \ - break - -QCursor& QtData::getCursor(PointerStyle ePointerStyle) -{ - if (!m_aCursors[ePointerStyle]) - { - QCursor* pCursor = nullptr; - - switch (ePointerStyle) - { - MAP_BUILTIN(PointerStyle::Arrow, Qt::ArrowCursor); - MAP_BUILTIN(PointerStyle::Text, Qt::IBeamCursor); - MAP_BUILTIN(PointerStyle::Help, Qt::WhatsThisCursor); - MAP_BUILTIN(PointerStyle::Cross, Qt::CrossCursor); - MAP_BUILTIN(PointerStyle::Wait, Qt::WaitCursor); - MAP_BUILTIN(PointerStyle::NSize, Qt::SizeVerCursor); - MAP_BUILTIN(PointerStyle::SSize, Qt::SizeVerCursor); - MAP_BUILTIN(PointerStyle::WSize, Qt::SizeHorCursor); - MAP_BUILTIN(PointerStyle::ESize, Qt::SizeHorCursor); - - MAP_BUILTIN(PointerStyle::NWSize, Qt::SizeFDiagCursor); - MAP_BUILTIN(PointerStyle::NESize, Qt::SizeBDiagCursor); - MAP_BUILTIN(PointerStyle::SWSize, Qt::SizeBDiagCursor); - MAP_BUILTIN(PointerStyle::SESize, Qt::SizeFDiagCursor); - MAP_BUILTIN(PointerStyle::WindowNSize, Qt::SizeVerCursor); - MAP_BUILTIN(PointerStyle::WindowSSize, Qt::SizeVerCursor); - MAP_BUILTIN(PointerStyle::WindowWSize, Qt::SizeHorCursor); - MAP_BUILTIN(PointerStyle::WindowESize, Qt::SizeHorCursor); - MAP_BUILTIN(PointerStyle::WindowNWSize, Qt::SizeFDiagCursor); - MAP_BUILTIN(PointerStyle::WindowNESize, Qt::SizeBDiagCursor); - MAP_BUILTIN(PointerStyle::WindowSWSize, Qt::SizeBDiagCursor); - MAP_BUILTIN(PointerStyle::WindowSESize, Qt::SizeFDiagCursor); - - MAP_BUILTIN(PointerStyle::HSizeBar, Qt::SizeHorCursor); - MAP_BUILTIN(PointerStyle::VSizeBar, Qt::SizeVerCursor); - - MAP_BUILTIN(PointerStyle::RefHand, Qt::OpenHandCursor); - MAP_BUILTIN(PointerStyle::Hand, Qt::OpenHandCursor); -#if 0 - MAP_BUILTIN( PointerStyle::Pen, GDK_PENCIL ); -#endif - MAP_BUILTIN(PointerStyle::HSplit, Qt::SizeHorCursor); - MAP_BUILTIN(PointerStyle::VSplit, Qt::SizeVerCursor); - - MAP_BUILTIN(PointerStyle::Move, Qt::SizeAllCursor); - - MAP_BUILTIN(PointerStyle::Null, Qt::BlankCursor); - MAKE_CURSOR(PointerStyle::Magnify, magnify_); - MAKE_CURSOR(PointerStyle::Fill, fill_); - MAKE_CURSOR(PointerStyle::MoveData, movedata_); - MAKE_CURSOR(PointerStyle::CopyData, copydata_); - MAKE_CURSOR(PointerStyle::MoveFile, movefile_); - MAKE_CURSOR(PointerStyle::CopyFile, copyfile_); - MAKE_CURSOR(PointerStyle::MoveFiles, movefiles_); - MAKE_CURSOR(PointerStyle::CopyFiles, copyfiles_); - MAKE_CURSOR(PointerStyle::NotAllowed, nodrop_); - MAKE_CURSOR(PointerStyle::Rotate, rotate_); - MAKE_CURSOR(PointerStyle::HShear, hshear_); - MAKE_CURSOR(PointerStyle::VShear, vshear_); - MAKE_CURSOR(PointerStyle::DrawLine, drawline_); - MAKE_CURSOR(PointerStyle::DrawRect, drawrect_); - MAKE_CURSOR(PointerStyle::DrawPolygon, drawpolygon_); - MAKE_CURSOR(PointerStyle::DrawBezier, drawbezier_); - MAKE_CURSOR(PointerStyle::DrawArc, drawarc_); - MAKE_CURSOR(PointerStyle::DrawPie, drawpie_); - MAKE_CURSOR(PointerStyle::DrawCircleCut, drawcirclecut_); - MAKE_CURSOR(PointerStyle::DrawEllipse, drawellipse_); - MAKE_CURSOR(PointerStyle::DrawConnect, drawconnect_); - MAKE_CURSOR(PointerStyle::DrawText, drawtext_); - MAKE_CURSOR(PointerStyle::Mirror, mirror_); - MAKE_CURSOR(PointerStyle::Crook, crook_); - MAKE_CURSOR(PointerStyle::Crop, crop_); - MAKE_CURSOR(PointerStyle::MovePoint, movepoint_); - MAKE_CURSOR(PointerStyle::MoveBezierWeight, movebezierweight_); - MAKE_CURSOR(PointerStyle::DrawFreehand, drawfreehand_); - MAKE_CURSOR(PointerStyle::DrawCaption, drawcaption_); - MAKE_CURSOR(PointerStyle::LinkData, linkdata_); - MAKE_CURSOR(PointerStyle::MoveDataLink, movedlnk_); - MAKE_CURSOR(PointerStyle::CopyDataLink, copydlnk_); - MAKE_CURSOR(PointerStyle::LinkFile, linkfile_); - MAKE_CURSOR(PointerStyle::MoveFileLink, moveflnk_); - MAKE_CURSOR(PointerStyle::CopyFileLink, copyflnk_); - MAKE_CURSOR(PointerStyle::Chart, chart_); - MAKE_CURSOR(PointerStyle::Detective, detective_); - MAKE_CURSOR(PointerStyle::PivotCol, pivotcol_); - MAKE_CURSOR(PointerStyle::PivotRow, pivotrow_); - MAKE_CURSOR(PointerStyle::PivotField, pivotfld_); - MAKE_CURSOR(PointerStyle::PivotDelete, pivotdel_); - MAKE_CURSOR(PointerStyle::Chain, chain_); - MAKE_CURSOR(PointerStyle::ChainNotAllowed, chainnot_); - MAKE_CURSOR(PointerStyle::AutoScrollN, asn_); - MAKE_CURSOR(PointerStyle::AutoScrollS, ass_); - MAKE_CURSOR(PointerStyle::AutoScrollW, asw_); - MAKE_CURSOR(PointerStyle::AutoScrollE, ase_); - MAKE_CURSOR(PointerStyle::AutoScrollNW, asnw_); - MAKE_CURSOR(PointerStyle::AutoScrollNE, asne_); - MAKE_CURSOR(PointerStyle::AutoScrollSW, assw_); - MAKE_CURSOR(PointerStyle::AutoScrollSE, asse_); - MAKE_CURSOR(PointerStyle::AutoScrollNS, asns_); - MAKE_CURSOR(PointerStyle::AutoScrollWE, aswe_); - MAKE_CURSOR(PointerStyle::AutoScrollNSWE, asnswe_); - MAKE_CURSOR(PointerStyle::TextVertical, vertcurs_); - - MAKE_CURSOR(PointerStyle::TabSelectS, tblsels_); - MAKE_CURSOR(PointerStyle::TabSelectE, tblsele_); - MAKE_CURSOR(PointerStyle::TabSelectSE, tblselse_); - MAKE_CURSOR(PointerStyle::TabSelectW, tblselw_); - MAKE_CURSOR(PointerStyle::TabSelectSW, tblselsw_); - - MAKE_CURSOR(PointerStyle::HideWhitespace, hidewhitespace_); - MAKE_CURSOR(PointerStyle::ShowWhitespace, showwhitespace_); - - MAKE_CURSOR(PointerStyle::FatCross, fatcross_); - default: - break; - } - if (!pCursor) - { - pCursor = new QCursor(Qt::ArrowCursor); - SAL_WARN("vcl.qt5", - "pointer " << static_cast<int>(ePointerStyle) << " not implemented"); - } - - m_aCursors[ePointerStyle].reset(pCursor); - } - - return *m_aCursors[ePointerStyle]; -} - -void QtData::ErrorTrapPush() {} - -bool QtData::ErrorTrapPop(bool /*bIgnoreError*/) { return false; } - -bool QtData::noNativeControls() -{ - static const bool bNoNative - = ((nullptr != getenv("SAL_VCL_QT5_NO_NATIVE")) && (nullptr != ImplGetSVData()) - && ImplGetSVData()->maAppData.mxToolkitName - && ImplGetSVData()->maAppData.mxToolkitName->match("qt5")); - return bNoNative; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5DragAndDrop.cxx b/vcl/qt5/Qt5DragAndDrop.cxx deleted file mode 100644 index 184cf07a6c5e..000000000000 --- a/vcl/qt5/Qt5DragAndDrop.cxx +++ /dev/null @@ -1,252 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <com/sun/star/awt/MouseButton.hpp> -#include <com/sun/star/datatransfer/DataFlavor.hpp> -#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> -#include <cppuhelper/supportsservice.hxx> -#include <sal/log.hxx> - -#include <Qt5DragAndDrop.hxx> -#include <Qt5Frame.hxx> -#include <Qt5Transferable.hxx> -#include <Qt5Widget.hxx> - -#include <QtGui/QDrag> - -using namespace com::sun::star; - -QtDragSource::~QtDragSource() {} - -void QtDragSource::deinitialize() { m_pFrame = nullptr; } - -sal_Bool QtDragSource::isDragImageSupported() { return true; } - -sal_Int32 QtDragSource::getDefaultCursor(sal_Int8) { return 0; } - -void QtDragSource::initialize(const css::uno::Sequence<css::uno::Any>& rArguments) -{ - if (rArguments.getLength() < 2) - { - throw uno::RuntimeException("DragSource::initialize: Cannot install window event handler", - static_cast<OWeakObject*>(this)); - } - - sal_IntPtr nFrame = 0; - rArguments.getConstArray()[1] >>= nFrame; - - if (!nFrame) - { - throw uno::RuntimeException("DragSource::initialize: missing SalFrame", - static_cast<OWeakObject*>(this)); - } - - m_pFrame = reinterpret_cast<QtFrame*>(nFrame); - m_pFrame->registerDragSource(this); -} - -void QtDragSource::startDrag( - const datatransfer::dnd::DragGestureEvent& /*rEvent*/, sal_Int8 sourceActions, - sal_Int32 /*cursor*/, sal_Int32 /*image*/, - const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, - const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener) -{ - m_xListener = rListener; - - if (m_pFrame) - { - QDrag* drag = new QDrag(m_pFrame->GetQWidget()); - drag->setMimeData(new QtMimeData(rTrans)); - // just a reminder that exec starts a nested event loop, so everything after - // this call is just executed, after D'n'D has finished! - drag->exec(toQtDropActions(sourceActions), getPreferredDropAction(sourceActions)); - } - - // the drop will eventually call fire_dragEnd, which will clear the listener. - // if D'n'D ends without success, we just get a leave event without any indicator, - // but the event loop will be terminated, so we have to try to inform the source of - // a failure in any way. - fire_dragEnd(datatransfer::dnd::DNDConstants::ACTION_NONE, false); -} - -void QtDragSource::fire_dragEnd(sal_Int8 nAction, bool bDropSuccessful) -{ - if (!m_xListener.is()) - return; - - datatransfer::dnd::DragSourceDropEvent aEv; - aEv.DropAction = nAction; - aEv.DropSuccess = bDropSuccessful; - - auto xListener = m_xListener; - m_xListener.clear(); - xListener->dragDropEnd(aEv); -} - -OUString SAL_CALL QtDragSource::getImplementationName() -{ - return "com.sun.star.datatransfer.dnd.VclQtDragSource"; -} - -sal_Bool SAL_CALL QtDragSource::supportsService(OUString const& ServiceName) -{ - return cppu::supportsService(this, ServiceName); -} - -css::uno::Sequence<OUString> SAL_CALL QtDragSource::getSupportedServiceNames() -{ - return { "com.sun.star.datatransfer.dnd.QtDragSource" }; -} - -QtDropTarget::QtDropTarget() - : WeakComponentImplHelper(m_aMutex) - , m_pFrame(nullptr) - , m_bActive(false) - , m_nDefaultActions(0) -{ -} - -OUString SAL_CALL QtDropTarget::getImplementationName() -{ - return "com.sun.star.datatransfer.dnd.VclQtDropTarget"; -} - -sal_Bool SAL_CALL QtDropTarget::supportsService(OUString const& ServiceName) -{ - return cppu::supportsService(this, ServiceName); -} - -css::uno::Sequence<OUString> SAL_CALL QtDropTarget::getSupportedServiceNames() -{ - return { "com.sun.star.datatransfer.dnd.QtDropTarget" }; -} - -QtDropTarget::~QtDropTarget() {} - -void QtDropTarget::deinitialize() -{ - m_pFrame = nullptr; - m_bActive = false; -} - -void QtDropTarget::initialize(const uno::Sequence<uno::Any>& rArguments) -{ - if (rArguments.getLength() < 2) - { - throw uno::RuntimeException("DropTarget::initialize: Cannot install window event handler", - static_cast<OWeakObject*>(this)); - } - - sal_IntPtr nFrame = 0; - rArguments.getConstArray()[1] >>= nFrame; - - if (!nFrame) - { - throw uno::RuntimeException("DropTarget::initialize: missing SalFrame", - static_cast<OWeakObject*>(this)); - } - - m_nDropAction = datatransfer::dnd::DNDConstants::ACTION_NONE; - - m_pFrame = reinterpret_cast<QtFrame*>(nFrame); - m_pFrame->registerDropTarget(this); - m_bActive = true; -} - -void QtDropTarget::addDropTargetListener( - const uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) -{ - ::osl::Guard<::osl::Mutex> aGuard(m_aMutex); - - m_aListeners.push_back(xListener); -} - -void QtDropTarget::removeDropTargetListener( - const uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) -{ - ::osl::Guard<::osl::Mutex> aGuard(m_aMutex); - - m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), xListener), - m_aListeners.end()); -} - -sal_Bool QtDropTarget::isActive() { return m_bActive; } - -void QtDropTarget::setActive(sal_Bool bActive) { m_bActive = bActive; } - -sal_Int8 QtDropTarget::getDefaultActions() { return m_nDefaultActions; } - -void QtDropTarget::setDefaultActions(sal_Int8 nDefaultActions) -{ - m_nDefaultActions = nDefaultActions; -} - -void QtDropTarget::fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde) -{ - osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); - std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( - m_aListeners); - aGuard.clear(); - - for (auto const& listener : aListeners) - { - listener->dragEnter(dtde); - } -} - -void QtDropTarget::fire_dragOver(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde) -{ - osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); - std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( - m_aListeners); - aGuard.clear(); - - for (auto const& listener : aListeners) - listener->dragOver(dtde); -} - -void QtDropTarget::fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) -{ - m_bDropSuccessful = true; - - osl::ClearableGuard<osl::Mutex> aGuard(m_aMutex); - std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( - m_aListeners); - aGuard.clear(); - - for (auto const& listener : aListeners) - listener->drop(dtde); -} - -void QtDropTarget::fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte) -{ - osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); - std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( - m_aListeners); - aGuard.clear(); - - for (auto const& listener : aListeners) - listener->dragExit(dte); -} - -void QtDropTarget::acceptDrag(sal_Int8 dragOperation) { m_nDropAction = dragOperation; } - -void QtDropTarget::rejectDrag() { m_nDropAction = 0; } - -void QtDropTarget::acceptDrop(sal_Int8 dropOperation) { m_nDropAction = dropOperation; } - -void QtDropTarget::rejectDrop() { m_nDropAction = 0; } - -void QtDropTarget::dropComplete(sal_Bool success) -{ - m_bDropSuccessful = (m_bDropSuccessful && success); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5FilePicker.cxx b/vcl/qt5/Qt5FilePicker.cxx deleted file mode 100644 index e2f733ca4fca..000000000000 --- a/vcl/qt5/Qt5FilePicker.cxx +++ /dev/null @@ -1,945 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5FilePicker.hxx> -#include <Qt5FilePicker.moc> - -#include <Qt5Frame.hxx> -#include <Qt5Tools.hxx> -#include <Qt5Widget.hxx> -#include <Qt5Instance.hxx> - -#include <com/sun/star/awt/SystemDependentXWindow.hpp> -#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> -#include <com/sun/star/awt/XWindow.hpp> -#include <com/sun/star/frame/Desktop.hpp> -#include <com/sun/star/frame/TerminationVetoException.hpp> -#include <com/sun/star/frame/XDesktop.hpp> -#include <com/sun/star/lang/DisposedException.hpp> -#include <com/sun/star/lang/IllegalArgumentException.hpp> -#include <com/sun/star/lang/SystemDependent.hpp> -#include <com/sun/star/lang/XMultiServiceFactory.hpp> -#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> -#include <com/sun/star/ui/dialogs/ControlActions.hpp> -#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> -#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> -#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> -#include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp> -#include <cppuhelper/interfacecontainer.h> -#include <cppuhelper/supportsservice.hxx> -#include <rtl/process.h> -#include <sal/log.hxx> - -#include <QtCore/QDebug> -#include <QtCore/QRegularExpression> -#include <QtCore/QThread> -#include <QtCore/QUrl> -#include <QtGui/QClipboard> -#include <QtGui/QWindow> -#include <QtWidgets/QApplication> -#include <QtWidgets/QCheckBox> -#include <QtWidgets/QComboBox> -#include <QtWidgets/QGridLayout> -#include <QtWidgets/QHBoxLayout> -#include <QtWidgets/QLabel> -#include <QtWidgets/QMessageBox> -#include <QtWidgets/QPushButton> -#include <QtWidgets/QWidget> - -#include <unx/geninst.h> -#include <strings.hrc> - -using namespace ::com::sun::star; -using namespace ::com::sun::star::ui::dialogs; -using namespace ::com::sun::star::ui::dialogs::TemplateDescription; -using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds; -using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds; -using namespace ::com::sun::star::lang; -using namespace ::com::sun::star::beans; -using namespace ::com::sun::star::uno; - -namespace -{ -uno::Sequence<OUString> FilePicker_getSupportedServiceNames() -{ - return { "com.sun.star.ui.dialogs.FilePicker", "com.sun.star.ui.dialogs.SystemFilePicker", - "com.sun.star.ui.dialogs.QtFilePicker" }; -} -} - -QtFilePicker::QtFilePicker(css::uno::Reference<css::uno::XComponentContext> const& context, - QFileDialog::FileMode eMode, bool bUseNative) - : QtFilePicker_Base(m_aHelperMutex) - , m_context(context) - , m_bIsFolderPicker(eMode == QFileDialog::Directory) - , m_pParentWidget(nullptr) - , m_pFileDialog(new QFileDialog(nullptr, {}, QDir::homePath())) - , m_pExtraControls(new QWidget()) -{ - m_pFileDialog->setOption(QFileDialog::DontUseNativeDialog, !bUseNative); - - m_pFileDialog->setFileMode(eMode); - m_pFileDialog->setWindowModality(Qt::ApplicationModal); - - if (m_bIsFolderPicker) - { - m_pFileDialog->setOption(QFileDialog::ShowDirsOnly, true); - m_pFileDialog->setWindowTitle(toQString(VclResId(STR_FPICKER_FOLDER_DEFAULT_TITLE))); - } - - m_pLayout = dynamic_cast<QGridLayout*>(m_pFileDialog->layout()); - - setMultiSelectionMode(false); - - // XFilePickerListener notifications - connect(m_pFileDialog.get(), SIGNAL(filterSelected(const QString&)), this, - SLOT(filterSelected(const QString&))); - connect(m_pFileDialog.get(), SIGNAL(currentChanged(const QString&)), this, - SLOT(currentChanged(const QString&))); - - // update automatic file extension when filter is changed - connect(m_pFileDialog.get(), SIGNAL(filterSelected(const QString&)), this, - SLOT(updateAutomaticFileExtension())); -} - -QtFilePicker::~QtFilePicker() -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this]() { - // must delete it in main thread, otherwise - // QSocketNotifier::setEnabled() will crash us - m_pFileDialog.reset(); - }); -} - -void SAL_CALL -QtFilePicker::addFilePickerListener(const uno::Reference<XFilePickerListener>& xListener) -{ - SolarMutexGuard aGuard; - m_xListener = xListener; -} - -void SAL_CALL QtFilePicker::removeFilePickerListener(const uno::Reference<XFilePickerListener>&) -{ - SolarMutexGuard aGuard; - m_xListener.clear(); -} - -void SAL_CALL QtFilePicker::setTitle(const OUString& title) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread( - [this, &title]() { m_pFileDialog->setWindowTitle(toQString(title)); }); -} - -sal_Int16 SAL_CALL QtFilePicker::execute() -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - sal_uInt16 ret; - pSalInst->RunInMainThread([&ret, this]() { ret = execute(); }); - return ret; - } - - QWidget* pTransientParent = m_pParentWidget; - if (!pTransientParent) - { - vcl::Window* pWindow = ::Application::GetActiveTopWindow(); - if (pWindow) - { - QtFrame* pFrame = dynamic_cast<QtFrame*>(pWindow->ImplGetFrame()); - assert(pFrame); - if (pFrame) - pTransientParent = pFrame->asChild(); - } - } - - if (!m_aNamedFilterList.isEmpty()) - m_pFileDialog->setNameFilters(m_aNamedFilterList); - if (!m_aCurrentFilter.isEmpty()) - m_pFileDialog->selectNameFilter(m_aCurrentFilter); - - updateAutomaticFileExtension(); - - uno::Reference<css::frame::XDesktop> xDesktop(css::frame::Desktop::create(m_context), - UNO_QUERY_THROW); - - // will hide the window, so do before show - m_pFileDialog->setParent(pTransientParent, m_pFileDialog->windowFlags()); - m_pFileDialog->show(); - xDesktop->addTerminateListener(this); - int result = m_pFileDialog->exec(); - xDesktop->removeTerminateListener(this); - m_pFileDialog->setParent(nullptr, m_pFileDialog->windowFlags()); - - if (QFileDialog::Rejected == result) - return ExecutableDialogResults::CANCEL; - return ExecutableDialogResults::OK; -} - -void SAL_CALL QtFilePicker::setMultiSelectionMode(sal_Bool multiSelect) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this, multiSelect]() { - if (m_bIsFolderPicker || m_pFileDialog->acceptMode() == QFileDialog::AcceptSave) - return; - - m_pFileDialog->setFileMode(multiSelect ? QFileDialog::ExistingFiles - : QFileDialog::ExistingFile); - }); -} - -void SAL_CALL QtFilePicker::setDefaultName(const OUString& name) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this, &name]() { m_pFileDialog->selectFile(toQString(name)); }); -} - -void SAL_CALL QtFilePicker::setDisplayDirectory(const OUString& dir) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this, &dir]() { - QString qDir(toQString(dir)); - m_pFileDialog->setDirectoryUrl(QUrl(qDir)); - }); -} - -OUString SAL_CALL QtFilePicker::getDisplayDirectory() -{ - SolarMutexGuard g; - OUString ret; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread( - [&ret, this]() { ret = toOUString(m_pFileDialog->directoryUrl().toString()); }); - return ret; -} - -uno::Sequence<OUString> SAL_CALL QtFilePicker::getFiles() -{ - uno::Sequence<OUString> seq = getSelectedFiles(); - if (seq.getLength() > 1) - seq.realloc(1); - return seq; -} - -uno::Sequence<OUString> SAL_CALL QtFilePicker::getSelectedFiles() -{ - SolarMutexGuard g; - QList<QUrl> urls; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([&urls, this]() { urls = m_pFileDialog->selectedUrls(); }); - - uno::Sequence<OUString> seq(urls.size()); - - auto const trans = css::uri::ExternalUriReferenceTranslator::create(m_context); - size_t i = 0; - for (const QUrl& aURL : urls) - { - // Unlike LO, QFileDialog (<https://doc.qt.io/qt-5/qfiledialog.html>) apparently always - // treats file-system pathnames as UTF-8--encoded, regardless of LANG/LC_CTYPE locale - // setting. And pathnames containing byte sequences that are not valid UTF-8 are apparently - // filtered out and not even displayed by QFileDialog, so aURL will always have a "payload" - // that matches the pathname's byte sequence. So the pathname's byte sequence (which - // happens to also be aURL's payload) in the LANG/LC_CTYPE encoding needs to be converted - // into LO's internal UTF-8 file URL encoding via - // XExternalUriReferenceTranslator::translateToInternal (which looks somewhat paradoxical as - // aURL.toEncoded() nominally already has a UTF-8 payload): - auto const extUrl = toOUString(aURL.toEncoded()); - auto intUrl = trans->translateToInternal(extUrl); - if (intUrl.isEmpty()) - { - // If translation failed, fall back to original URL: - SAL_WARN("vcl.qt5", "cannot convert <" << extUrl << "> from locale encoding to UTF-8"); - intUrl = extUrl; - } - seq[i++] = intUrl; - } - - return seq; -} - -void SAL_CALL QtFilePicker::appendFilter(const OUString& title, const OUString& filter) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - pSalInst->RunInMainThread([this, &title, &filter]() { appendFilter(title, filter); }); - return; - } - - // '/' need to be escaped else they are assumed to be mime types - QString sTitle = toQString(title).replace("/", "\\/"); - - QString sFilterName = sTitle; - // the Qt non-native file picker adds the extensions to the filter title, so strip them - if (m_pFileDialog->testOption(QFileDialog::DontUseNativeDialog)) - { - int pos = sFilterName.indexOf(" ("); - if (pos >= 0) - sFilterName.truncate(pos); - } - - QString sGlobFilter = toQString(filter); - - // LibreOffice gives us filters separated by ';' qt dialogs just want space separated - sGlobFilter.replace(";", " "); - - // make sure "*.*" is not used as "all files" - sGlobFilter.replace("*.*", "*"); - - m_aNamedFilterList << QStringLiteral("%1 (%2)").arg(sFilterName, sGlobFilter); - m_aTitleToFilterMap[sTitle] = m_aNamedFilterList.constLast(); - m_aNamedFilterToExtensionMap[m_aNamedFilterList.constLast()] = sGlobFilter; -} - -void SAL_CALL QtFilePicker::setCurrentFilter(const OUString& title) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this, &title]() { - m_aCurrentFilter = m_aTitleToFilterMap.value(toQString(title).replace("/", "\\/")); - }); -} - -OUString SAL_CALL QtFilePicker::getCurrentFilter() -{ - SolarMutexGuard g; - QString filter; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([&filter, this]() { - filter = m_aTitleToFilterMap.key(m_pFileDialog->selectedNameFilter()); - }); - - if (filter.isEmpty()) - filter = "ODF Text Document (.odt)"; - return toOUString(filter); -} - -void SAL_CALL QtFilePicker::appendFilterGroup(const OUString& rGroupTitle, - const uno::Sequence<beans::StringPair>& filters) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - pSalInst->RunInMainThread( - [this, &rGroupTitle, &filters]() { appendFilterGroup(rGroupTitle, filters); }); - return; - } - - const sal_uInt16 length = filters.getLength(); - for (sal_uInt16 i = 0; i < length; ++i) - { - beans::StringPair aPair = filters[i]; - appendFilter(aPair.First, aPair.Second); - } -} - -uno::Any QtFilePicker::handleGetListValue(const QComboBox* pWidget, sal_Int16 nControlAction) -{ - uno::Any aAny; - switch (nControlAction) - { - case ControlActions::GET_ITEMS: - { - Sequence<OUString> aItemList(pWidget->count()); - for (sal_Int32 i = 0; i < pWidget->count(); ++i) - aItemList[i] = toOUString(pWidget->itemText(i)); - aAny <<= aItemList; - break; - } - case ControlActions::GET_SELECTED_ITEM: - { - if (!pWidget->currentText().isEmpty()) - aAny <<= toOUString(pWidget->currentText()); - break; - } - case ControlActions::GET_SELECTED_ITEM_INDEX: - { - if (pWidget->currentIndex() >= 0) - aAny <<= static_cast<sal_Int32>(pWidget->currentIndex()); - break; - } - default: - SAL_WARN("vcl.qt5", - "undocumented/unimplemented ControlAction for a list " << nControlAction); - break; - } - return aAny; -} - -void QtFilePicker::handleSetListValue(QComboBox* pWidget, sal_Int16 nControlAction, - const uno::Any& rValue) -{ - switch (nControlAction) - { - case ControlActions::ADD_ITEM: - { - OUString sItem; - rValue >>= sItem; - pWidget->addItem(toQString(sItem)); - break; - } - case ControlActions::ADD_ITEMS: - { - Sequence<OUString> aStringList; - rValue >>= aStringList; - for (auto const& sItem : std::as_const(aStringList)) - pWidget->addItem(toQString(sItem)); - break; - } - case ControlActions::DELETE_ITEM: - { - sal_Int32 nPos = 0; - rValue >>= nPos; - pWidget->removeItem(nPos); - break; - } - case ControlActions::DELETE_ITEMS: - { - pWidget->clear(); - break; - } - case ControlActions::SET_SELECT_ITEM: - { - sal_Int32 nPos = 0; - rValue >>= nPos; - pWidget->setCurrentIndex(nPos); - break; - } - default: - SAL_WARN("vcl.qt5", - "undocumented/unimplemented ControlAction for a list " << nControlAction); - break; - } - - pWidget->setEnabled(pWidget->count() > 0); -} - -void SAL_CALL QtFilePicker::setValue(sal_Int16 controlId, sal_Int16 nControlAction, - const uno::Any& value) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - pSalInst->RunInMainThread([this, controlId, nControlAction, &value]() { - setValue(controlId, nControlAction, value); - }); - return; - } - - if (m_aCustomWidgetsMap.contains(controlId)) - { - QWidget* widget = m_aCustomWidgetsMap.value(controlId); - QCheckBox* cb = dynamic_cast<QCheckBox*>(widget); - if (cb) - cb->setChecked(value.get<bool>()); - else - { - QComboBox* combo = dynamic_cast<QComboBox*>(widget); - if (combo) - handleSetListValue(combo, nControlAction, value); - } - } - else - SAL_WARN("vcl.qt5", "set value on unknown control " << controlId); -} - -uno::Any SAL_CALL QtFilePicker::getValue(sal_Int16 controlId, sal_Int16 nControlAction) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - uno::Any ret; - pSalInst->RunInMainThread([&ret, this, controlId, nControlAction]() { - ret = getValue(controlId, nControlAction); - }); - return ret; - } - - uno::Any res(false); - if (m_aCustomWidgetsMap.contains(controlId)) - { - QWidget* widget = m_aCustomWidgetsMap.value(controlId); - QCheckBox* cb = dynamic_cast<QCheckBox*>(widget); - if (cb) - res <<= cb->isChecked(); - else - { - QComboBox* combo = dynamic_cast<QComboBox*>(widget); - if (combo) - res = handleGetListValue(combo, nControlAction); - } - } - else - SAL_WARN("vcl.qt5", "get value on unknown control " << controlId); - - return res; -} - -void SAL_CALL QtFilePicker::enableControl(sal_Int16 controlId, sal_Bool enable) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this, controlId, enable]() { - if (m_aCustomWidgetsMap.contains(controlId)) - m_aCustomWidgetsMap.value(controlId)->setEnabled(enable); - else - SAL_WARN("vcl.qt5", "enable unknown control " << controlId); - }); -} - -void SAL_CALL QtFilePicker::setLabel(sal_Int16 controlId, const OUString& label) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - pSalInst->RunInMainThread([this, controlId, label]() { setLabel(controlId, label); }); - return; - } - - if (m_aCustomWidgetsMap.contains(controlId)) - { - QCheckBox* cb = dynamic_cast<QCheckBox*>(m_aCustomWidgetsMap.value(controlId)); - if (cb) - cb->setText(toQString(label)); - } - else - SAL_WARN("vcl.qt5", "set label on unknown control " << controlId); -} - -OUString SAL_CALL QtFilePicker::getLabel(sal_Int16 controlId) -{ - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - OUString ret; - pSalInst->RunInMainThread([&ret, this, controlId]() { ret = getLabel(controlId); }); - return ret; - } - - QString label; - if (m_aCustomWidgetsMap.contains(controlId)) - { - QCheckBox* cb = dynamic_cast<QCheckBox*>(m_aCustomWidgetsMap.value(controlId)); - if (cb) - label = cb->text(); - } - else - SAL_WARN("vcl.qt5", "get label on unknown control " << controlId); - - return toOUString(label); -} - -QString QtFilePicker::getResString(TranslateId pResId) -{ - QString aResString; - - if (!pResId) - return aResString; - - aResString = toQString(VclResId(pResId)); - - return aResString.replace('~', '&'); -} - -void QtFilePicker::addCustomControl(sal_Int16 controlId) -{ - QWidget* widget = nullptr; - QLabel* label = nullptr; - TranslateId resId; - QCheckBox* pCheckbox = nullptr; - - switch (controlId) - { - case CHECKBOX_AUTOEXTENSION: - resId = STR_FPICKER_AUTO_EXTENSION; - break; - case CHECKBOX_PASSWORD: - resId = STR_FPICKER_PASSWORD; - break; - case CHECKBOX_FILTEROPTIONS: - resId = STR_FPICKER_FILTER_OPTIONS; - break; - case CHECKBOX_READONLY: - resId = STR_FPICKER_READONLY; - break; - case CHECKBOX_LINK: - resId = STR_FPICKER_INSERT_AS_LINK; - break; - case CHECKBOX_PREVIEW: - resId = STR_FPICKER_SHOW_PREVIEW; - break; - case CHECKBOX_SELECTION: - resId = STR_FPICKER_SELECTION; - break; - case CHECKBOX_GPGENCRYPTION: - resId = STR_FPICKER_GPGENCRYPT; - break; - case PUSHBUTTON_PLAY: - resId = STR_FPICKER_PLAY; - break; - case LISTBOX_VERSION: - resId = STR_FPICKER_VERSION; - break; - case LISTBOX_TEMPLATE: - resId = STR_FPICKER_TEMPLATES; - break; - case LISTBOX_IMAGE_TEMPLATE: - resId = STR_FPICKER_IMAGE_TEMPLATE; - break; - case LISTBOX_IMAGE_ANCHOR: - resId = STR_FPICKER_IMAGE_ANCHOR; - break; - case LISTBOX_VERSION_LABEL: - case LISTBOX_TEMPLATE_LABEL: - case LISTBOX_IMAGE_TEMPLATE_LABEL: - case LISTBOX_IMAGE_ANCHOR_LABEL: - case LISTBOX_FILTER_SELECTOR: - break; - } - - switch (controlId) - { - case CHECKBOX_AUTOEXTENSION: - pCheckbox = new QCheckBox(getResString(resId), m_pExtraControls); - // to add/remove automatic file extension based on checkbox - connect(pCheckbox, SIGNAL(stateChanged(int)), this, - SLOT(updateAutomaticFileExtension())); - widget = pCheckbox; - break; - case CHECKBOX_PASSWORD: - case CHECKBOX_FILTEROPTIONS: - case CHECKBOX_READONLY: - case CHECKBOX_LINK: - case CHECKBOX_PREVIEW: - case CHECKBOX_SELECTION: - case CHECKBOX_GPGENCRYPTION: - widget = new QCheckBox(getResString(resId), m_pExtraControls); - break; - case PUSHBUTTON_PLAY: - break; - case LISTBOX_VERSION: - case LISTBOX_TEMPLATE: - case LISTBOX_IMAGE_ANCHOR: - case LISTBOX_IMAGE_TEMPLATE: - case LISTBOX_FILTER_SELECTOR: - label = new QLabel(getResString(resId), m_pExtraControls); - widget = new QComboBox(m_pExtraControls); - label->setBuddy(widget); - break; - case LISTBOX_VERSION_LABEL: - case LISTBOX_TEMPLATE_LABEL: - case LISTBOX_IMAGE_TEMPLATE_LABEL: - case LISTBOX_IMAGE_ANCHOR_LABEL: - break; - } - - if (widget) - { - const int row = m_pLayout->rowCount(); - if (label) - m_pLayout->addWidget(label, row, 0); - m_pLayout->addWidget(widget, row, 1); - m_aCustomWidgetsMap.insert(controlId, widget); - } -} - -void SAL_CALL QtFilePicker::initialize(const uno::Sequence<uno::Any>& args) -{ - // parameter checking - uno::Any arg; - if (args.getLength() == 0) - throw lang::IllegalArgumentException("no arguments", static_cast<XFilePicker2*>(this), 1); - - arg = args[0]; - - if ((arg.getValueType() != cppu::UnoType<sal_Int16>::get()) - && (arg.getValueType() != cppu::UnoType<sal_Int8>::get())) - { - throw lang::IllegalArgumentException("invalid argument type", - static_cast<XFilePicker2*>(this), 1); - } - - SolarMutexGuard g; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - pSalInst->RunInMainThread([this, args]() { initialize(args); }); - return; - } - - m_aNamedFilterToExtensionMap.clear(); - m_aNamedFilterList.clear(); - m_aTitleToFilterMap.clear(); - m_aCurrentFilter.clear(); - - sal_Int16 templateId = -1; - arg >>= templateId; - - QFileDialog::AcceptMode acceptMode = QFileDialog::AcceptOpen; - switch (templateId) - { - case FILEOPEN_SIMPLE: - break; - - case FILESAVE_SIMPLE: - acceptMode = QFileDialog::AcceptSave; - break; - - case FILESAVE_AUTOEXTENSION: - acceptMode = QFileDialog::AcceptSave; - addCustomControl(CHECKBOX_AUTOEXTENSION); - break; - - case FILESAVE_AUTOEXTENSION_PASSWORD: - acceptMode = QFileDialog::AcceptSave; - addCustomControl(CHECKBOX_AUTOEXTENSION); - addCustomControl(CHECKBOX_PASSWORD); - addCustomControl(CHECKBOX_GPGENCRYPTION); - break; - - case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS: - acceptMode = QFileDialog::AcceptSave; - addCustomControl(CHECKBOX_AUTOEXTENSION); - addCustomControl(CHECKBOX_PASSWORD); - addCustomControl(CHECKBOX_GPGENCRYPTION); - addCustomControl(CHECKBOX_FILTEROPTIONS); - break; - - case FILESAVE_AUTOEXTENSION_SELECTION: - acceptMode = QFileDialog::AcceptSave; - addCustomControl(CHECKBOX_AUTOEXTENSION); - addCustomControl(CHECKBOX_SELECTION); - break; - - case FILESAVE_AUTOEXTENSION_TEMPLATE: - acceptMode = QFileDialog::AcceptSave; - addCustomControl(CHECKBOX_AUTOEXTENSION); - addCustomControl(LISTBOX_TEMPLATE); - break; - - case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE: - addCustomControl(CHECKBOX_LINK); - addCustomControl(CHECKBOX_PREVIEW); - addCustomControl(LISTBOX_IMAGE_TEMPLATE); - break; - - case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR: - addCustomControl(CHECKBOX_LINK); - addCustomControl(CHECKBOX_PREVIEW); - addCustomControl(LISTBOX_IMAGE_ANCHOR); - break; - - case FILEOPEN_PLAY: - addCustomControl(PUSHBUTTON_PLAY); - break; - - case FILEOPEN_LINK_PLAY: - addCustomControl(CHECKBOX_LINK); - addCustomControl(PUSHBUTTON_PLAY); - break; - - case FILEOPEN_READONLY_VERSION: - addCustomControl(CHECKBOX_READONLY); - addCustomControl(LISTBOX_VERSION); - break; - - case FILEOPEN_LINK_PREVIEW: - addCustomControl(CHECKBOX_LINK); - addCustomControl(CHECKBOX_PREVIEW); - break; - - case FILEOPEN_PREVIEW: - addCustomControl(CHECKBOX_PREVIEW); - break; - - default: - throw lang::IllegalArgumentException("Unknown template", - static_cast<XFilePicker2*>(this), 1); - } - - TranslateId resId; - switch (acceptMode) - { - case QFileDialog::AcceptOpen: - resId = STR_FPICKER_OPEN; - break; - case QFileDialog::AcceptSave: - resId = STR_FPICKER_SAVE; - m_pFileDialog->setFileMode(QFileDialog::AnyFile); - break; - } - - m_pFileDialog->setAcceptMode(acceptMode); - m_pFileDialog->setWindowTitle(getResString(resId)); - - css::uno::Reference<css::awt::XWindow> xParentWindow; - if (args.getLength() > 1) - args[1] >>= xParentWindow; - if (!xParentWindow.is()) - return; - - css::uno::Reference<css::awt::XSystemDependentWindowPeer> xSysWinPeer(xParentWindow, - css::uno::UNO_QUERY); - if (!xSysWinPeer.is()) - return; - - // the sal_*Int8 handling is strange, but it's public API - no way around - css::uno::Sequence<sal_Int8> aProcessIdent(16); - rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8*>(aProcessIdent.getArray())); - uno::Any aAny - = xSysWinPeer->getWindowHandle(aProcessIdent, css::lang::SystemDependent::SYSTEM_XWINDOW); - css::awt::SystemDependentXWindow xSysWin; - aAny >>= xSysWin; - - const auto& pFrames = pSalInst->getFrames(); - const tools::Long aWindowHandle = xSysWin.WindowHandle; - const auto it - = std::find_if(pFrames.begin(), pFrames.end(), [&aWindowHandle](auto pFrame) -> bool { - const SystemEnvData* pData = pFrame->GetSystemData(); - return pData && tools::Long(pData->GetWindowHandle(pFrame)) == aWindowHandle; - }); - if (it != pFrames.end()) - m_pParentWidget = static_cast<QtFrame*>(*it)->asChild(); -} - -void SAL_CALL QtFilePicker::cancel() { m_pFileDialog->reject(); } - -void SAL_CALL QtFilePicker::disposing(const lang::EventObject& rEvent) -{ - uno::Reference<XFilePickerListener> xFilePickerListener(rEvent.Source, uno::UNO_QUERY); - - if (xFilePickerListener.is()) - { - removeFilePickerListener(xFilePickerListener); - } -} - -void SAL_CALL QtFilePicker::queryTermination(const css::lang::EventObject&) -{ - throw css::frame::TerminationVetoException(); -} - -void SAL_CALL QtFilePicker::notifyTermination(const css::lang::EventObject&) -{ - SolarMutexGuard aGuard; - m_pFileDialog->reject(); -} - -OUString SAL_CALL QtFilePicker::getImplementationName() -{ - return "com.sun.star.ui.dialogs.QtFilePicker"; -} - -sal_Bool SAL_CALL QtFilePicker::supportsService(const OUString& ServiceName) -{ - return cppu::supportsService(this, ServiceName); -} - -uno::Sequence<OUString> SAL_CALL QtFilePicker::getSupportedServiceNames() -{ - return FilePicker_getSupportedServiceNames(); -} - -void QtFilePicker::updateAutomaticFileExtension() -{ - bool bSetAutoExtension - = getValue(CHECKBOX_AUTOEXTENSION, ControlActions::GET_SELECTED_ITEM).get<bool>(); - if (bSetAutoExtension) - { - QString sSuffix = m_aNamedFilterToExtensionMap.value(m_pFileDialog->selectedNameFilter()); - // string is "*.<SUFFIX>" if a specific filter was selected that has exactly one possible file extension - if (sSuffix.lastIndexOf("*.") == 0) - { - sSuffix = sSuffix.remove("*."); - m_pFileDialog->setDefaultSuffix(sSuffix); - } - else - { - // fall back to setting none otherwise - SAL_INFO( - "vcl.qt5", - "Unable to retrieve unambiguous file extension. Will not add any automatically."); - bSetAutoExtension = false; - } - } - - if (!bSetAutoExtension) - m_pFileDialog->setDefaultSuffix(""); -} - -void QtFilePicker::filterSelected(const QString&) -{ - FilePickerEvent aEvent; - aEvent.ElementId = LISTBOX_FILTER; - SAL_INFO("vcl.qt5", "filter changed"); - if (m_xListener.is()) - m_xListener->controlStateChanged(aEvent); -} - -void QtFilePicker::currentChanged(const QString&) -{ - FilePickerEvent aEvent; - SAL_INFO("vcl.qt5", "file selection changed"); - if (m_xListener.is()) - m_xListener->fileSelectionChanged(aEvent); -} - -OUString QtFilePicker::getDirectory() -{ - uno::Sequence<OUString> seq = getSelectedFiles(); - if (seq.getLength() > 1) - seq.realloc(1); - return seq[0]; -} - -void QtFilePicker::setDescription(const OUString&) {} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Font.cxx b/vcl/qt5/Qt5Font.cxx deleted file mode 100644 index a230ea1560e7..000000000000 --- a/vcl/qt5/Qt5Font.cxx +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * 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 <Qt5Font.hxx> -#include <Qt5Tools.hxx> - -#include <QtGui/QFont> -#include <QtGui/QRawFont> - -static inline void applyWeight(QtFont& rFont, FontWeight eWeight) -{ - switch (eWeight) - { - case WEIGHT_THIN: - rFont.setWeight(QFont::Thin); - break; - case WEIGHT_ULTRALIGHT: - rFont.setWeight(QFont::ExtraLight); - break; - case WEIGHT_LIGHT: - rFont.setWeight(QFont::Light); - break; - case WEIGHT_SEMILIGHT: - [[fallthrough]]; - case WEIGHT_NORMAL: - rFont.setWeight(QFont::Normal); - break; - case WEIGHT_MEDIUM: - rFont.setWeight(QFont::Medium); - break; - case WEIGHT_SEMIBOLD: - rFont.setWeight(QFont::DemiBold); - break; - case WEIGHT_BOLD: - rFont.setWeight(QFont::Bold); - break; - case WEIGHT_ULTRABOLD: - rFont.setWeight(QFont::ExtraBold); - break; - case WEIGHT_BLACK: - rFont.setWeight(QFont::Black); - break; - default: - break; - } -} - -static inline void applyStretch(QtFont& rFont, FontWidth eWidthType) -{ - switch (eWidthType) - { - case WIDTH_DONTKNOW: - rFont.setStretch(QFont::AnyStretch); - break; - case WIDTH_ULTRA_CONDENSED: - rFont.setStretch(QFont::UltraCondensed); - break; - case WIDTH_EXTRA_CONDENSED: - rFont.setStretch(QFont::ExtraCondensed); - break; - case WIDTH_CONDENSED: - rFont.setStretch(QFont::Condensed); - break; - case WIDTH_SEMI_CONDENSED: - rFont.setStretch(QFont::SemiCondensed); - break; - case WIDTH_NORMAL: - rFont.setStretch(QFont::Unstretched); - break; - case WIDTH_SEMI_EXPANDED: - rFont.setStretch(QFont::SemiExpanded); - break; - case WIDTH_EXPANDED: - rFont.setStretch(QFont::Expanded); - break; - case WIDTH_EXTRA_EXPANDED: - rFont.setStretch(QFont::ExtraExpanded); - break; - case WIDTH_ULTRA_EXPANDED: - rFont.setStretch(QFont::UltraExpanded); - break; - default: - break; - } -} - -static inline void applyStyle(QtFont& rFont, FontItalic eItalic) -{ - switch (eItalic) - { - case ITALIC_NONE: - rFont.setStyle(QFont::Style::StyleNormal); - break; - case ITALIC_OBLIQUE: - rFont.setStyle(QFont::Style::StyleOblique); - break; - case ITALIC_NORMAL: - rFont.setStyle(QFont::Style::StyleItalic); - break; - default: - break; - } -} - -QtFont::QtFont(const PhysicalFontFace& rPFF, const vcl::font::FontSelectPattern& rFSP) - : LogicalFontInstance(rPFF, rFSP) -{ - setFamily(toQString(rPFF.GetFamilyName())); - applyWeight(*this, rPFF.GetWeight()); - setPixelSize(rFSP.mnHeight); - applyStretch(*this, rPFF.GetWidthType()); - applyStyle(*this, rFSP.GetItalic()); -} - -static hb_blob_t* getFontTable(hb_face_t*, hb_tag_t nTableTag, void* pUserData) -{ - char pTagName[5]; - LogicalFontInstance::DecodeOpenTypeTag(nTableTag, pTagName); - - QtFont* pFont = static_cast<QtFont*>(pUserData); - QRawFont aRawFont(QRawFont::fromFont(*pFont)); - QByteArray aTable = aRawFont.fontTable(pTagName); - const sal_uInt32 nLength = aTable.size(); - - hb_blob_t* pBlob = nullptr; - if (nLength > 0) - pBlob = hb_blob_create(aTable.data(), nLength, HB_MEMORY_MODE_DUPLICATE, nullptr, nullptr); - return pBlob; -} - -hb_font_t* QtFont::ImplInitHbFont() -{ - return InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr)); -} - -bool QtFont::GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const { return false; } - -bool QtFont::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool) const -{ - QRawFont aRawFont(QRawFont::fromFont(*this)); - rRect = toRectangle(aRawFont.boundingRect(nId).toAlignedRect()); - return true; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5FontFace.cxx b/vcl/qt5/Qt5FontFace.cxx deleted file mode 100644 index b690c6abcf4f..000000000000 --- a/vcl/qt5/Qt5FontFace.cxx +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * 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 <unotools/fontdefs.hxx> - -#include <Qt5FontFace.hxx> -#include <Qt5Font.hxx> -#include <Qt5Tools.hxx> - -#include <sft.hxx> -#include <impfontcharmap.hxx> -#include <fontinstance.hxx> -#include <font/FontSelectPattern.hxx> -#include <PhysicalFontCollection.hxx> - -#include <QtGui/QFont> -#include <QtGui/QFontDatabase> -#include <QtGui/QFontInfo> -#include <QtGui/QRawFont> - -using namespace vcl; - -QtFontFace::QtFontFace(const QtFontFace& rSrc) - : PhysicalFontFace(rSrc) - , m_aFontId(rSrc.m_aFontId) - , m_eFontIdType(rSrc.m_eFontIdType) -{ - if (rSrc.m_xCharMap.is()) - m_xCharMap = rSrc.m_xCharMap; -} - -FontWeight QtFontFace::toFontWeight(const int nWeight) -{ - if (nWeight <= QFont::Thin) - return WEIGHT_THIN; - if (nWeight <= QFont::ExtraLight) - return WEIGHT_ULTRALIGHT; - if (nWeight <= QFont::Light) - return WEIGHT_LIGHT; - if (nWeight <= QFont::Normal) - return WEIGHT_NORMAL; - if (nWeight <= QFont::Medium) - return WEIGHT_MEDIUM; - if (nWeight <= QFont::DemiBold) - return WEIGHT_SEMIBOLD; - if (nWeight <= QFont::Bold) - return WEIGHT_BOLD; - if (nWeight <= QFont::ExtraBold) - return WEIGHT_ULTRABOLD; - return WEIGHT_BLACK; -} - -FontWidth QtFontFace::toFontWidth(const int nStretch) -{ - if (nStretch == 0) // QFont::AnyStretch since Qt 5.8 - return WIDTH_DONTKNOW; - if (nStretch <= QFont::UltraCondensed) - return WIDTH_ULTRA_CONDENSED; - if (nStretch <= QFont::ExtraCondensed) - return WIDTH_EXTRA_CONDENSED; - if (nStretch <= QFont::Condensed) - return WIDTH_CONDENSED; - if (nStretch <= QFont::SemiCondensed) - return WIDTH_SEMI_CONDENSED; - if (nStretch <= QFont::Unstretched) - return WIDTH_NORMAL; - if (nStretch <= QFont::SemiExpanded) - return WIDTH_SEMI_EXPANDED; - if (nStretch <= QFont::Expanded) - return WIDTH_EXPANDED; - if (nStretch <= QFont::ExtraExpanded) - return WIDTH_EXTRA_EXPANDED; - return WIDTH_ULTRA_EXPANDED; -} - -FontItalic QtFontFace::toFontItalic(const QFont::Style eStyle) -{ - switch (eStyle) - { - case QFont::StyleNormal: - return ITALIC_NONE; - case QFont::StyleItalic: - return ITALIC_NORMAL; - case QFont::StyleOblique: - return ITALIC_OBLIQUE; - } - - return ITALIC_NONE; -} - -void QtFontFace::fillAttributesFromQFont(const QFont& rFont, FontAttributes& rFA) -{ - QFontInfo aFontInfo(rFont); - - rFA.SetFamilyName(toOUString(aFontInfo.family())); - if (IsStarSymbol(toOUString(aFontInfo.family()))) - rFA.SetSymbolFlag(true); - rFA.SetStyleName(toOUString(aFontInfo.styleName())); - rFA.SetPitch(aFontInfo.fixedPitch() ? PITCH_FIXED : PITCH_VARIABLE); - rFA.SetWeight(QtFontFace::toFontWeight(aFontInfo.weight())); - rFA.SetItalic(QtFontFace::toFontItalic(aFontInfo.style())); - rFA.SetWidthType(QtFontFace::toFontWidth(rFont.stretch())); -} - -QtFontFace* QtFontFace::fromQFont(const QFont& rFont) -{ - FontAttributes aFA; - fillAttributesFromQFont(rFont, aFA); - return new QtFontFace(aFA, rFont.toString(), FontIdType::Font); -} - -QtFontFace* QtFontFace::fromQFontDatabase(const QString& aFamily, const QString& aStyle) -{ - QFontDatabase aFDB; - FontAttributes aFA; - - aFA.SetFamilyName(toOUString(aFamily)); - if (IsStarSymbol(aFA.GetFamilyName())) - aFA.SetSymbolFlag(true); - aFA.SetStyleName(toOUString(aStyle)); - aFA.SetPitch(aFDB.isFixedPitch(aFamily, aStyle) ? PITCH_FIXED : PITCH_VARIABLE); - aFA.SetWeight(QtFontFace::toFontWeight(aFDB.weight(aFamily, aStyle))); - aFA.SetItalic(aFDB.italic(aFamily, aStyle) ? ITALIC_NORMAL : ITALIC_NONE); - - int nPointSize = 0; - QList<int> aPointList = aFDB.pointSizes(aFamily, aStyle); - if (!aPointList.empty()) - nPointSize = aPointList[0]; - - return new QtFontFace(aFA, aFamily + "," + aStyle + "," + QString::number(nPointSize), - FontIdType::FontDB); -} - -QtFontFace::QtFontFace(const FontAttributes& rFA, const QString& rFontID, - const FontIdType eFontIdType) - : PhysicalFontFace(rFA) - , m_aFontId(rFontID) - , m_eFontIdType(eFontIdType) - , m_bFontCapabilitiesRead(false) -{ -} - -sal_IntPtr QtFontFace::GetFontId() const { return reinterpret_cast<sal_IntPtr>(&m_aFontId); } - -QFont QtFontFace::CreateFont() const -{ - QFont aFont; - switch (m_eFontIdType) - { - case FontDB: - { - QFontDatabase aFDB; - QStringList aStrList = m_aFontId.split(","); - if (3 == aStrList.size()) - aFont = aFDB.font(aStrList[0], aStrList[1], aStrList[2].toInt()); - else - SAL_WARN("vcl.qt5", "Invalid QFontDatabase font ID " << m_aFontId); - break; - } - case Font: - bool bRet = aFont.fromString(m_aFontId); - SAL_WARN_IF(!bRet, "vcl.qt5", "Failed to create QFont from ID: " << m_aFontId); - Q_UNUSED(bRet); - break; - } - return aFont; -} - -rtl::Reference<LogicalFontInstance> -QtFontFace::CreateFontInstance(const vcl::font::FontSelectPattern& rFSD) const -{ - return new QtFont(*this, rFSD); -} - -FontCharMapRef QtFontFace::GetFontCharMap() const -{ - if (m_xCharMap.is()) - return m_xCharMap; - - QFont aFont = CreateFont(); - QRawFont aRawFont(QRawFont::fromFont(aFont)); - QByteArray aCMapTable = aRawFont.fontTable("cmap"); - if (aCMapTable.isEmpty()) - { - m_xCharMap = new FontCharMap(); - return m_xCharMap; - } - - CmapResult aCmapResult; - if (ParseCMAP(reinterpret_cast<const unsigned char*>(aCMapTable.data()), aCMapTable.size(), - aCmapResult)) - m_xCharMap = new FontCharMap(aCmapResult); - - return m_xCharMap; -} - -bool QtFontFace::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const -{ - // read this only once per font - if (m_bFontCapabilitiesRead) - { - rFontCapabilities = m_aFontCapabilities; - return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; - } - m_bFontCapabilitiesRead = true; - - QFont aFont = CreateFont(); - QRawFont aRawFont(QRawFont::fromFont(aFont)); - QByteArray aOS2Table = aRawFont.fontTable("OS/2"); - if (!aOS2Table.isEmpty()) - { - vcl::getTTCoverage(m_aFontCapabilities.oUnicodeRange, m_aFontCapabilities.oCodePageRange, - reinterpret_cast<const unsigned char*>(aOS2Table.data()), - aOS2Table.size()); - } - - rFontCapabilities = m_aFontCapabilities; - return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Frame.cxx b/vcl/qt5/Qt5Frame.cxx deleted file mode 100644 index 7f1bf041ae20..000000000000 --- a/vcl/qt5/Qt5Frame.cxx +++ /dev/null @@ -1,1452 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Frame.hxx> -#include <Qt5Frame.moc> - -#include <Qt5Data.hxx> -#include <Qt5DragAndDrop.hxx> -#include <Qt5Graphics.hxx> -#include <Qt5Instance.hxx> -#include <Qt5MainWindow.hxx> -#include <Qt5Menu.hxx> -#include <Qt5SvpGraphics.hxx> -#include <Qt5System.hxx> -#include <Qt5Tools.hxx> -#include <Qt5Transferable.hxx> -#include <Qt5Widget.hxx> - -#include <QtCore/QMimeData> -#include <QtCore/QPoint> -#include <QtCore/QSize> -#include <QtCore/QThread> -#include <QtCore/QVersionNumber> -#include <QtGui/QDragMoveEvent> -#include <QtGui/QDropEvent> -#include <QtGui/QIcon> -#include <QtGui/QWindow> -#include <QtGui/QScreen> -#include <QtWidgets/QStyle> -#include <QtWidgets/QToolTip> -#include <QtWidgets/QApplication> -#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) -#include <QtWidgets/QDesktopWidget> -#endif -#include <QtWidgets/QMenuBar> -#include <QtWidgets/QMainWindow> - -#if QT5_USING_X11 -#include <QtX11Extras/QX11Info> -#include <xcb/xproto.h> -#if QT5_HAVE_XCB_ICCCM -#include <xcb/xcb_icccm.h> -#endif -#endif - -#include <saldatabasic.hxx> -#include <window.h> -#include <vcl/syswin.hxx> - -#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> - -#include <cairo.h> -#include <headless/svpgdi.hxx> - -#if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM -static bool g_bNeedsWmHintsWindowGroup = true; -static xcb_atom_t g_aXcbClientLeaderAtom = 0; -#endif - -static void SvpDamageHandler(void* handle, sal_Int32 nExtentsX, sal_Int32 nExtentsY, - sal_Int32 nExtentsWidth, sal_Int32 nExtentsHeight) -{ - QtFrame* pThis = static_cast<QtFrame*>(handle); - pThis->Damage(nExtentsX, nExtentsY, nExtentsWidth, nExtentsHeight); -} - -namespace -{ -sal_Int32 screenNumber(const QScreen* pScreen) -{ - const QList<QScreen*> screens = QApplication::screens(); - - sal_Int32 nScreen = 0; - bool bFound = false; - for (const QScreen* pCurScreen : screens) - { - if (pScreen == pCurScreen) - { - bFound = true; - break; - } - nScreen++; - } - - return bFound ? nScreen : -1; -} -} - -QtFrame::QtFrame(QtFrame* pParent, SalFrameStyleFlags nStyle, bool bUseCairo) - : m_pTopLevel(nullptr) - , m_bUseCairo(bUseCairo) - , m_bNullRegion(true) - , m_bGraphicsInUse(false) - , m_ePointerStyle(PointerStyle::Arrow) - , m_pDragSource(nullptr) - , m_pDropTarget(nullptr) - , m_bInDrag(false) - , m_bDefaultSize(true) - , m_bDefaultPos(true) - , m_bFullScreen(false) - , m_bFullScreenSpanAll(false) -#if QT5_USING_X11 - , m_nKeyModifiers(ModKeyFlags::NONE) -#endif - , m_nInputLanguage(LANGUAGE_DONTKNOW) -{ - QtInstance* pInst = static_cast<QtInstance*>(GetSalData()->m_pInstance); - pInst->insertFrame(this); - - m_aDamageHandler.handle = this; - m_aDamageHandler.damaged = ::SvpDamageHandler; - - if (nStyle & SalFrameStyleFlags::DEFAULT) // ensure default style - { - nStyle |= SalFrameStyleFlags::MOVEABLE | SalFrameStyleFlags::SIZEABLE - | SalFrameStyleFlags::CLOSEABLE; - nStyle &= ~SalFrameStyleFlags::FLOAT; - } - - m_nStyle = nStyle; - m_pParent = pParent; - - Qt::WindowFlags aWinFlags; - if (!(nStyle & SalFrameStyleFlags::SYSTEMCHILD)) - { - if (nStyle & SalFrameStyleFlags::INTRO) - aWinFlags |= Qt::SplashScreen; - // floating toolbars are frameless tool windows - // + they must be able to receive keyboard focus - else if ((nStyle & SalFrameStyleFlags::FLOAT) - && (nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)) - aWinFlags |= Qt::Tool | Qt::FramelessWindowHint; - else if (nStyle & SalFrameStyleFlags::TOOLTIP) - aWinFlags |= Qt::ToolTip; - // Can't use Qt::Popup, because it grabs the input focus and generates - // a focus-out event, reaching the combo box. This used to map to - // Qt::ToolTip, which doesn't feel that correct... - else if (isPopup()) - aWinFlags = Qt::Widget | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint; - else if (nStyle & SalFrameStyleFlags::TOOLWINDOW) - aWinFlags |= Qt::Tool; - // top level windows can't be transient in Qt, so make them dialogs, if they have a parent. At least - // the plasma shell relies on this setting to skip dialogs in the window list. And Qt Xcb will just - // set transient for the types Dialog, Sheet, Tool, SplashScreen, ToolTip, Drawer and Popup. - else if (nStyle & SalFrameStyleFlags::DIALOG || m_pParent) - aWinFlags |= Qt::Dialog; - else - aWinFlags |= Qt::Window; - } - - if (aWinFlags == Qt::Window) - { - m_pTopLevel = new QtMainWindow(*this, aWinFlags); - m_pQWidget = new QtWidget(*this, aWinFlags); - m_pTopLevel->setCentralWidget(m_pQWidget); - m_pTopLevel->setFocusProxy(m_pQWidget); - } - else - m_pQWidget = new QtWidget(*this, aWinFlags); - - if (pParent && !(pParent->m_nStyle & SalFrameStyleFlags::PLUG)) - { - QWindow* pParentWindow = pParent->GetQWidget()->window()->windowHandle(); - QWindow* pChildWindow = asChild()->window()->windowHandle(); - if (pParentWindow && pChildWindow && (pParentWindow != pChildWindow)) - pChildWindow->setTransientParent(pParentWindow); - } - - // Calling 'QWidget::winId()' implicitly enables native windows to be used - // rather than "alien widgets" that are unknown to the windowing system, - // s. https://doc.qt.io/qt-5/qwidget.html#native-widgets-vs-alien-widgets - // Avoid this on Wayland due to problems with missing 'mouseMoveEvent's, - // s. tdf#122293/QTBUG-75766 - const bool bWayland = QGuiApplication::platformName() == "wayland"; - if (!bWayland) - m_aSystemData.SetWindowHandle(m_pQWidget->winId()); - else - { - // TODO implement as needed for Wayland, - // s.a. commit c0d4f3ad3307c which did this for gtk3 - // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface(); - // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr); - // m_aSystemData.aWindow = reinterpret_cast<unsigned long>( - // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle())); - } - - m_aSystemData.aShellWindow = reinterpret_cast<sal_IntPtr>(this); - //m_aSystemData.pSalFrame = this; - m_aSystemData.pWidget = m_pQWidget; - //m_aSystemData.nScreen = m_nXScreen.getXScreen(); - m_aSystemData.toolkit = SystemEnvData::Toolkit::Qt5; - if (!bWayland) - m_aSystemData.platform = SystemEnvData::Platform::Xcb; - else - m_aSystemData.platform = SystemEnvData::Platform::Wayland; - - SetIcon(SV_ICON_ID_OFFICE); - - fixICCCMwindowGroup(); -} - -void QtFrame::fixICCCMwindowGroup() -{ -#if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM - // older Qt5 just sets WM_CLIENT_LEADER, but not the XCB_ICCCM_WM_HINT_WINDOW_GROUP - // see Qt commit 0de4b326d8 ("xcb: fix issue with dialogs hidden by other windows") - // or QTBUG-46626. So LO has to set this itself to help some WMs. - if (!g_bNeedsWmHintsWindowGroup) - return; - g_bNeedsWmHintsWindowGroup = false; - - if (QGuiApplication::platformName() != "xcb") - return; - if (QVersionNumber::fromString(qVersion()) >= QVersionNumber(5, 12)) - return; - - xcb_connection_t* conn = QX11Info::connection(); - xcb_window_t win = asChild()->winId(); - - xcb_icccm_wm_hints_t hints; - - xcb_get_property_cookie_t prop_cookie = xcb_icccm_get_wm_hints_unchecked(conn, win); - if (!xcb_icccm_get_wm_hints_reply(conn, prop_cookie, &hints, nullptr)) - return; - - if (hints.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP) - return; - - if (g_aXcbClientLeaderAtom == 0) - { - const char* const leader_name = "WM_CLIENT_LEADER\0"; - xcb_intern_atom_cookie_t atom_cookie - = xcb_intern_atom(conn, 1, strlen(leader_name), leader_name); - xcb_intern_atom_reply_t* atom_reply = xcb_intern_atom_reply(conn, atom_cookie, nullptr); - if (!atom_reply) - return; - g_aXcbClientLeaderAtom = atom_reply->atom; - free(atom_reply); - } - - g_bNeedsWmHintsWindowGroup = true; - - prop_cookie = xcb_get_property(conn, 0, win, g_aXcbClientLeaderAtom, XCB_ATOM_WINDOW, 0, 1); - xcb_get_property_reply_t* prop_reply = xcb_get_property_reply(conn, prop_cookie, nullptr); - if (!prop_reply) - return; - - if (xcb_get_property_value_length(prop_reply) != 4) - { - free(prop_reply); - return; - } - - xcb_window_t leader = *static_cast<xcb_window_t*>(xcb_get_property_value(prop_reply)); - free(prop_reply); - - hints.flags |= XCB_ICCCM_WM_HINT_WINDOW_GROUP; - hints.window_group = leader; - xcb_icccm_set_wm_hints(conn, win, &hints); -#else - (void)this; // avoid loplugin:staticmethods -#endif -} - -QtFrame::~QtFrame() -{ - QtInstance* pInst = static_cast<QtInstance*>(GetSalData()->m_pInstance); - pInst->eraseFrame(this); - delete asChild(); - m_aSystemData.aShellWindow = 0; -} - -void QtFrame::Damage(sal_Int32 nExtentsX, sal_Int32 nExtentsY, sal_Int32 nExtentsWidth, - sal_Int32 nExtentsHeight) const -{ - m_pQWidget->update(scaledQRect(QRect(nExtentsX, nExtentsY, nExtentsWidth, nExtentsHeight), - 1 / devicePixelRatioF())); -} - -SalGraphics* QtFrame::AcquireGraphics() -{ - if (m_bGraphicsInUse) - return nullptr; - - m_bGraphicsInUse = true; - - if (m_bUseCairo) - { - if (!m_pSvpGraphics) - { - QSize aSize = m_pQWidget->size() * devicePixelRatioF(); - m_pSvpGraphics.reset(new QtSvpGraphics(this)); - m_pSurface.reset( - cairo_image_surface_create(CAIRO_FORMAT_ARGB32, aSize.width(), aSize.height())); - m_pSvpGraphics->setSurface(m_pSurface.get(), - basegfx::B2IVector(aSize.width(), aSize.height())); - cairo_surface_set_user_data(m_pSurface.get(), QtSvpGraphics::getDamageKey(), - &m_aDamageHandler, nullptr); - } - return m_pSvpGraphics.get(); - } - else - { - if (!m_pQtGraphics) - { - m_pQtGraphics.reset(new QtGraphics(this)); - m_pQImage.reset( - new QImage(m_pQWidget->size() * devicePixelRatioF(), Qt_DefaultFormat32)); - m_pQImage->fill(Qt::transparent); - m_pQtGraphics->ChangeQImage(m_pQImage.get()); - } - return m_pQtGraphics.get(); - } -} - -void QtFrame::ReleaseGraphics(SalGraphics* pSalGraph) -{ - (void)pSalGraph; - if (m_bUseCairo) - assert(pSalGraph == m_pSvpGraphics.get()); - else - assert(pSalGraph == m_pQtGraphics.get()); - m_bGraphicsInUse = false; -} - -bool QtFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData) -{ - QtInstance* pInst = static_cast<QtInstance*>(GetSalData()->m_pInstance); - pInst->PostEvent(this, pData.release(), SalEvent::UserEvent); - return true; -} - -QWidget* QtFrame::asChild() const { return m_pTopLevel ? m_pTopLevel : m_pQWidget; } - -qreal QtFrame::devicePixelRatioF() const { return asChild()->devicePixelRatioF(); } - -bool QtFrame::isWindow() const { return asChild()->isWindow(); } - -QWindow* QtFrame::windowHandle() const -{ - // set attribute 'Qt::WA_NativeWindow' first to make sure a window handle actually exists - QWidget* pChild = asChild(); - pChild->setAttribute(Qt::WA_NativeWindow); - return pChild->windowHandle(); -} - -QScreen* QtFrame::screen() const -{ - QWindow* const pWindow = windowHandle(); - return pWindow ? pWindow->screen() : nullptr; -} - -bool QtFrame::isMinimized() const { return asChild()->isMinimized(); } - -bool QtFrame::isMaximized() const { return asChild()->isMaximized(); } - -void QtFrame::SetWindowStateImpl(Qt::WindowStates eState) -{ - return asChild()->setWindowState(eState); -} - -void QtFrame::SetTitle(const OUString& rTitle) -{ - m_pQWidget->window()->setWindowTitle(toQString(rTitle)); -} - -void QtFrame::SetIcon(sal_uInt16 nIcon) -{ - if (m_nStyle - & (SalFrameStyleFlags::PLUG | SalFrameStyleFlags::SYSTEMCHILD - | SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::INTRO - | SalFrameStyleFlags::OWNERDRAWDECORATION) - || !isWindow()) - return; - - QString appicon; - - if (nIcon == SV_ICON_ID_TEXT) - appicon = "libreoffice-writer"; - else if (nIcon == SV_ICON_ID_SPREADSHEET) - appicon = "libreoffice-calc"; - else if (nIcon == SV_ICON_ID_DRAWING) - appicon = "libreoffice-draw"; - else if (nIcon == SV_ICON_ID_PRESENTATION) - appicon = "libreoffice-impress"; - else if (nIcon == SV_ICON_ID_DATABASE) - appicon = "libreoffice-base"; - else if (nIcon == SV_ICON_ID_FORMULA) - appicon = "libreoffice-math"; - else - appicon = "libreoffice-startcenter"; - - QIcon aIcon = QIcon::fromTheme(appicon); - m_pQWidget->window()->setWindowIcon(aIcon); -} - -void QtFrame::SetMenu(SalMenu*) {} - -void QtFrame::DrawMenuBar() { /* not needed */} - -void QtFrame::SetExtendedFrameStyle(SalExtStyle /*nExtStyle*/) { /* not needed */} - -void QtFrame::Show(bool bVisible, bool bNoActivate) -{ - assert(m_pQWidget); - if (bVisible == asChild()->isVisible()) - return; - - SetDefaultSize(); - SetDefaultPos(); - - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this, bVisible, bNoActivate]() { - asChild()->setVisible(bVisible); - asChild()->raise(); - if (!bNoActivate && !isPopup()) - { - asChild()->activateWindow(); - asChild()->setFocus(); - } - }); -} - -void QtFrame::SetMinClientSize(tools::Long nWidth, tools::Long nHeight) -{ - if (!isChild()) - { - const qreal fRatio = devicePixelRatioF(); - asChild()->setMinimumSize(round(nWidth / fRatio), round(nHeight / fRatio)); - } -} - -void QtFrame::SetMaxClientSize(tools::Long nWidth, tools::Long nHeight) -{ - if (!isChild()) - { - const qreal fRatio = devicePixelRatioF(); - asChild()->setMaximumSize(round(nWidth / fRatio), round(nHeight / fRatio)); - } -} - -void QtFrame::SetDefaultPos() -{ - if (!m_bDefaultPos) - return; - - // center on parent - if (m_pParent) - { - const qreal fRatio = devicePixelRatioF(); - QWidget* const pWindow = m_pParent->GetQWidget()->window(); - QWidget* const pWidget = asChild(); - QPoint aPos = pWindow->rect().center() - pWidget->rect().center(); - SetPosSize(round(aPos.x() * fRatio), round(aPos.y() * fRatio), 0, 0, - SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y); - assert(!m_bDefaultPos); - } - else - m_bDefaultPos = false; -} - -Size QtFrame::CalcDefaultSize() -{ - assert(isWindow()); - - Size aSize; - if (!m_bFullScreen) - { - const QScreen* pScreen = screen(); - if (!pScreen) - pScreen = QGuiApplication::screens().at(0); - aSize = bestmaxFrameSizeForScreenSize(toSize(pScreen->size())); - } - else - { - if (!m_bFullScreenSpanAll) - { - aSize = toSize(QGuiApplication::screens().at(maGeometry.nDisplayScreenNumber)->size()); - } - else - { -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - QScreen* pScreen = QGuiApplication::screenAt(QPoint(0, 0)); -#else - // QGuiApplication::screenAt was added in Qt 5.10, use deprecated QDesktopWidget - int nLeftScreen = QApplication::desktop()->screenNumber(QPoint(0, 0)); - QScreen* pScreen = QGuiApplication::screens()[nLeftScreen]; -#endif - aSize = toSize(pScreen->availableVirtualGeometry().size()); - } - } - - return aSize; -} - -void QtFrame::SetDefaultSize() -{ - if (!m_bDefaultSize) - return; - - Size aDefSize = CalcDefaultSize(); - SetPosSize(0, 0, aDefSize.Width(), aDefSize.Height(), - SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT); - assert(!m_bDefaultSize); -} - -void QtFrame::SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, - sal_uInt16 nFlags) -{ - if (!isWindow() || isChild(true, false)) - return; - - if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) - { - if (isChild(false) || !m_pQWidget->isMaximized()) - { - if (!(nFlags & SAL_FRAME_POSSIZE_WIDTH)) - nWidth = maGeometry.nWidth; - else if (!(nFlags & SAL_FRAME_POSSIZE_HEIGHT)) - nHeight = maGeometry.nHeight; - - if (nWidth > 0 && nHeight > 0) - { - m_bDefaultSize = false; - const int nNewWidth = round(nWidth / devicePixelRatioF()); - const int nNewHeight = round(nHeight / devicePixelRatioF()); - if (m_nStyle & SalFrameStyleFlags::SIZEABLE) - asChild()->resize(nNewWidth, nNewHeight); - else - asChild()->setFixedSize(nNewWidth, nNewHeight); - } - - // assume the resize happened - // needed for calculations and will eventually be corrected by events - if (nWidth > 0) - maGeometry.nWidth = nWidth; - if (nHeight > 0) - maGeometry.nHeight = nHeight; - } - } - - if (!(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))) - return; - - if (m_pParent) - { - const SalFrameGeometry& aParentGeometry = m_pParent->maGeometry; - if (QGuiApplication::isRightToLeft()) - nX = aParentGeometry.nX + aParentGeometry.nWidth - nX - maGeometry.nWidth - 1; - else - nX += aParentGeometry.nX; - nY += aParentGeometry.nY; - - QtMainWindow* pTopLevel = m_pParent->GetTopLevelWindow(); - if (pTopLevel && pTopLevel->menuBar() && pTopLevel->menuBar()->isVisible()) - nY += round(pTopLevel->menuBar()->geometry().height() * devicePixelRatioF()); - } - - if (!(nFlags & SAL_FRAME_POSSIZE_X)) - nX = maGeometry.nX; - else if (!(nFlags & SAL_FRAME_POSSIZE_Y)) - nY = maGeometry.nY; - - // assume the reposition happened - // needed for calculations and will eventually be corrected by events later - maGeometry.nX = nX; - maGeometry.nY = nY; - - m_bDefaultPos = false; - asChild()->move(round(nX / devicePixelRatioF()), round(nY / devicePixelRatioF())); -} - -void QtFrame::GetClientSize(tools::Long& rWidth, tools::Long& rHeight) -{ - rWidth = round(m_pQWidget->width() * devicePixelRatioF()); - rHeight = round(m_pQWidget->height() * devicePixelRatioF()); -} - -void QtFrame::GetWorkArea(tools::Rectangle& rRect) -{ - if (!isWindow()) - return; - QScreen* pScreen = screen(); - if (!pScreen) - return; - - QSize aSize = pScreen->availableVirtualSize() * devicePixelRatioF(); - rRect = tools::Rectangle(0, 0, aSize.width(), aSize.height()); -} - -SalFrame* QtFrame::GetParent() const { return m_pParent; } - -void QtFrame::SetModal(bool bModal) -{ - if (!isWindow()) - return; - - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->RunInMainThread([this, bModal]() { - - QWidget* const pChild = asChild(); - const bool bWasVisible = pChild->isVisible(); - - // modality change is only effective if the window is hidden - if (bWasVisible) - pChild->hide(); - - pChild->setWindowModality(bModal ? Qt::WindowModal : Qt::NonModal); - - if (bWasVisible) - pChild->show(); - }); -} - -bool QtFrame::GetModal() const { return isWindow() && windowHandle()->isModal(); } - -void QtFrame::SetWindowState(const SalFrameState* pState) -{ - if (!isWindow() || !pState || isChild(true, false)) - return; - - const WindowStateMask nMaxGeometryMask - = WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width | WindowStateMask::Height - | WindowStateMask::MaximizedX | WindowStateMask::MaximizedY - | WindowStateMask::MaximizedWidth | WindowStateMask::MaximizedHeight; - - if ((pState->mnMask & WindowStateMask::State) && (pState->mnState & WindowStateState::Maximized) - && !isMaximized() && (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask) - { - const qreal fRatio = devicePixelRatioF(); - QWidget* const pChild = asChild(); - pChild->resize(ceil(pState->mnWidth / fRatio), ceil(pState->mnHeight / fRatio)); - pChild->move(ceil(pState->mnX / fRatio), ceil(pState->mnY / fRatio)); - SetWindowStateImpl(Qt::WindowMaximized); - } - else if (pState->mnMask - & (WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width - | WindowStateMask::Height)) - { - sal_uInt16 nPosSizeFlags = 0; - if (pState->mnMask & WindowStateMask::X) - nPosSizeFlags |= SAL_FRAME_POSSIZE_X; - if (pState->mnMask & WindowStateMask::Y) - nPosSizeFlags |= SAL_FRAME_POSSIZE_Y; - if (pState->mnMask & WindowStateMask::Width) - nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH; - if (pState->mnMask & WindowStateMask::Height) - nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT; - SetPosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nPosSizeFlags); - } - else if (pState->mnMask & WindowStateMask::State && !isChild()) - { - if (pState->mnState & WindowStateState::Maximized) - SetWindowStateImpl(Qt::WindowMaximized); - else if (pState->mnState & WindowStateState::Minimized) - SetWindowStateImpl(Qt::WindowMinimized); - else - SetWindowStateImpl(Qt::WindowNoState); - } -} - -bool QtFrame::GetWindowState(SalFrameState* pState) -{ - pState->mnState = WindowStateState::Normal; - pState->mnMask = WindowStateMask::State; - if (isMinimized() /*|| !windowHandle()*/) - pState->mnState |= WindowStateState::Minimized; - else if (isMaximized()) - { - pState->mnState |= WindowStateState::Maximized; - } - else - { - // geometry() is the drawable area, which is wanted here - QRect rect = scaledQRect(asChild()->geometry(), devicePixelRatioF()); - pState->mnX = rect.x(); - pState->mnY = rect.y(); - pState->mnWidth = rect.width(); - pState->mnHeight = rect.height(); - pState->mnMask |= WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width - | WindowStateMask::Height; - } - - return true; -} - -void QtFrame::ShowFullScreen(bool bFullScreen, sal_Int32 nScreen) -{ - // only top-level windows can go fullscreen - assert(m_pTopLevel); - - if (m_bFullScreen == bFullScreen) - return; - - m_bFullScreen = bFullScreen; - m_bFullScreenSpanAll = m_bFullScreen && (nScreen < 0); - - // show it if it isn't shown yet - if (!isWindow()) - m_pTopLevel->show(); - - if (m_bFullScreen) - { - m_aRestoreGeometry = m_pTopLevel->geometry(); - m_nRestoreScreen = maGeometry.nDisplayScreenNumber; - SetScreenNumber(m_bFullScreenSpanAll ? m_nRestoreScreen : nScreen); - if (!m_bFullScreenSpanAll) - windowHandle()->showFullScreen(); - else - windowHandle()->showNormal(); - } - else - { - SetScreenNumber(m_nRestoreScreen); - windowHandle()->showNormal(); - m_pTopLevel->setGeometry(m_aRestoreGeometry); - } -} - -void QtFrame::StartPresentation(bool bStart) -{ -// meh - so there's no Qt platform independent solution -// https://forum.qt.io/topic/38504/solved-qdialog-in-fullscreen-disable-os-screensaver -#if QT5_USING_X11 - std::optional<unsigned int> aRootWindow; - std::optional<Display*> aDisplay; - - if (QX11Info::isPlatformX11()) - { - aRootWindow = QX11Info::appRootWindow(); - aDisplay = QX11Info::display(); - } - - m_ScreenSaverInhibitor.inhibit(bStart, u"presentation", QX11Info::isPlatformX11(), aRootWindow, - aDisplay); -#else - (void)bStart; -#endif -} - -void QtFrame::SetAlwaysOnTop(bool bOnTop) -{ - QWidget* const pWidget = asChild(); - const Qt::WindowFlags flags = pWidget->windowFlags(); - if (bOnTop) - pWidget->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); - else - pWidget->setWindowFlags(flags & ~(Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint)); -} - -void QtFrame::ToTop(SalFrameToTop nFlags) -{ - QWidget* const pWidget = asChild(); - if (isWindow() && !(nFlags & SalFrameToTop::GrabFocusOnly)) - pWidget->raise(); - if ((nFlags & SalFrameToTop::RestoreWhenMin) || (nFlags & SalFrameToTop::ForegroundTask)) - pWidget->activateWindow(); - else if ((nFlags & SalFrameToTop::GrabFocus) || (nFlags & SalFrameToTop::GrabFocusOnly)) - { - pWidget->activateWindow(); - pWidget->setFocus(); - } -} - -void QtFrame::SetPointer(PointerStyle ePointerStyle) -{ - QWindow* pWindow = m_pQWidget->window()->windowHandle(); - if (!pWindow) - return; - if (ePointerStyle == m_ePointerStyle) - return; - m_ePointerStyle = ePointerStyle; - - pWindow->setCursor(static_cast<QtData*>(GetSalData())->getCursor(ePointerStyle)); -} - -void QtFrame::CaptureMouse(bool bMouse) -{ - static const char* pEnv = getenv("SAL_NO_MOUSEGRABS"); - if (pEnv && *pEnv) - return; - - if (bMouse) - m_pQWidget->grabMouse(); - else - m_pQWidget->releaseMouse(); -} - -void QtFrame::SetPointerPos(tools::Long nX, tools::Long nY) -{ - // some cursor already exists (and it has m_ePointerStyle shape) - // so here we just reposition it - QCursor::setPos(m_pQWidget->mapToGlobal(QPoint(nX, nY))); -} - -void QtFrame::Flush() -{ - // was: QGuiApplication::sync(); - // but FIXME it causes too many issues, figure out sth better - - // unclear if we need to also flush cairo surface - gtk3 backend - // does not do it. QPainter in QtWidget::paintEvent() is - // destroyed, so that state should be safely flushed. -} - -bool QtFrame::ShowTooltip(const OUString& rText, const tools::Rectangle& rHelpArea) -{ - QRect aHelpArea(toQRect(rHelpArea)); - if (QGuiApplication::isRightToLeft()) - aHelpArea.moveLeft(maGeometry.nWidth - aHelpArea.width() - aHelpArea.left() - 1); - QToolTip::showText(QCursor::pos(), toQString(rText), m_pQWidget, aHelpArea); - return true; -} - -void QtFrame::SetInputContext(SalInputContext* pContext) -{ - if (!pContext) - return; - - if (!(pContext->mnOptions & InputContextFlags::Text)) - return; - - m_pQWidget->setAttribute(Qt::WA_InputMethodEnabled); -} - -void QtFrame::EndExtTextInput(EndExtTextInputFlags /*nFlags*/) -{ - QtWidget* pQtWidget = static_cast<QtWidget*>(m_pQWidget); - if (pQtWidget) - pQtWidget->endExtTextInput(); -} - -OUString QtFrame::GetKeyName(sal_uInt16 nKeyCode) -{ - vcl::KeyCode vclKeyCode(nKeyCode); - int nCode = vclKeyCode.GetCode(); - int nRetCode = 0; - - if (nCode >= KEY_0 && nCode <= KEY_9) - nRetCode = (nCode - KEY_0) + Qt::Key_0; - else if (nCode >= KEY_A && nCode <= KEY_Z) - nRetCode = (nCode - KEY_A) + Qt::Key_A; - else if (nCode >= KEY_F1 && nCode <= KEY_F26) - nRetCode = (nCode - KEY_F1) + Qt::Key_F1; - else - { - switch (nCode) - { - case KEY_DOWN: - nRetCode = Qt::Key_Down; - break; - case KEY_UP: - nRetCode = Qt::Key_Up; - break; - case KEY_LEFT: - nRetCode = Qt::Key_Left; - break; - case KEY_RIGHT: - nRetCode = Qt::Key_Right; - break; - case KEY_HOME: - nRetCode = Qt::Key_Home; - break; - case KEY_END: - nRetCode = Qt::Key_End; - break; - case KEY_PAGEUP: - nRetCode = Qt::Key_PageUp; - break; - case KEY_PAGEDOWN: - nRetCode = Qt::Key_PageDown; - break; - case KEY_RETURN: - nRetCode = Qt::Key_Return; - break; - case KEY_ESCAPE: - nRetCode = Qt::Key_Escape; - break; - case KEY_TAB: - nRetCode = Qt::Key_Tab; - break; - case KEY_BACKSPACE: - nRetCode = Qt::Key_Backspace; - break; - case KEY_SPACE: - nRetCode = Qt::Key_Space; - break; - case KEY_INSERT: - nRetCode = Qt::Key_Insert; - break; - case KEY_DELETE: - nRetCode = Qt::Key_Delete; - break; - case KEY_ADD: - nRetCode = Qt::Key_Plus; - break; - case KEY_SUBTRACT: - nRetCode = Qt::Key_Minus; - break; - case KEY_MULTIPLY: - nRetCode = Qt::Key_Asterisk; - break; - case KEY_DIVIDE: - nRetCode = Qt::Key_Slash; - break; - case KEY_POINT: - nRetCode = Qt::Key_Period; - break; - case KEY_COMMA: - nRetCode = Qt::Key_Comma; - break; - case KEY_LESS: - nRetCode = Qt::Key_Less; - break; - case KEY_GREATER: - nRetCode = Qt::Key_Greater; - break; - case KEY_EQUAL: - nRetCode = Qt::Key_Equal; - break; - case KEY_FIND: - nRetCode = Qt::Key_Find; - break; - case KEY_CONTEXTMENU: - nRetCode = Qt::Key_Menu; - break; - case KEY_HELP: - nRetCode = Qt::Key_Help; - break; - case KEY_UNDO: - nRetCode = Qt::Key_Undo; - break; - case KEY_REPEAT: - nRetCode = Qt::Key_Redo; - break; - case KEY_TILDE: - nRetCode = Qt::Key_AsciiTilde; - break; - case KEY_QUOTELEFT: - nRetCode = Qt::Key_QuoteLeft; - break; - case KEY_BRACKETLEFT: - nRetCode = Qt::Key_BracketLeft; - break; - case KEY_BRACKETRIGHT: - nRetCode = Qt::Key_BracketRight; - break; - case KEY_SEMICOLON: - nRetCode = Qt::Key_Semicolon; - break; - - // Special cases - case KEY_COPY: - nRetCode = Qt::Key_Copy; - break; - case KEY_CUT: - nRetCode = Qt::Key_Cut; - break; - case KEY_PASTE: - nRetCode = Qt::Key_Paste; - break; - case KEY_OPEN: - nRetCode = Qt::Key_Open; - break; - } - } - - if (vclKeyCode.IsShift()) - nRetCode += Qt::SHIFT; - if (vclKeyCode.IsMod1()) - nRetCode += Qt::CTRL; - if (vclKeyCode.IsMod2()) - nRetCode += Qt::ALT; - - QKeySequence keySeq(nRetCode); - OUString sKeyName = toOUString(keySeq.toString()); - - return sKeyName; -} - -bool QtFrame::MapUnicodeToKeyCode(sal_Unicode /*aUnicode*/, LanguageType /*aLangType*/, - vcl::KeyCode& /*rKeyCode*/) -{ - // not supported yet - return false; -} - -LanguageType QtFrame::GetInputLanguage() { return m_nInputLanguage; } - -void QtFrame::setInputLanguage(LanguageType nInputLanguage) -{ - if (nInputLanguage == m_nInputLanguage) - return; - m_nInputLanguage = nInputLanguage; - CallCallback(SalEvent::InputLanguageChange, nullptr); -} - -static Color toColor(const QColor& rColor) -{ - return Color(rColor.red(), rColor.green(), rColor.blue()); -} - -void QtFrame::UpdateSettings(AllSettings& rSettings) -{ - if (QtData::noNativeControls()) - return; - - StyleSettings style(rSettings.GetStyleSettings()); - - // General settings - QPalette pal = QApplication::palette(); - - style.SetToolbarIconSize(ToolbarIconSize::Large); - - Color aFore = toColor(pal.color(QPalette::Active, QPalette::WindowText)); - Color aBack = toColor(pal.color(QPalette::Active, QPalette::Window)); - Color aText = toColor(pal.color(QPalette::Active, QPalette::Text)); - Color aBase = toColor(pal.color(QPalette::Active, QPalette::Base)); - Color aButn = toColor(pal.color(QPalette::Active, QPalette::ButtonText)); - Color aMid = toColor(pal.color(QPalette::Active, QPalette::Mid)); - Color aHigh = toColor(pal.color(QPalette::Active, QPalette::Highlight)); - Color aHighText = toColor(pal.color(QPalette::Active, QPalette::HighlightedText)); - Color aLink = toColor(pal.color(QPalette::Active, QPalette::Link)); - Color aVisitedLink = toColor(pal.color(QPalette::Active, QPalette::LinkVisited)); - - style.SetSkipDisabledInMenus(true); - - // Foreground - style.SetRadioCheckTextColor(aFore); - style.SetLabelTextColor(aFore); - style.SetDialogTextColor(aFore); - style.SetGroupTextColor(aFore); - - // Text - style.SetFieldTextColor(aText); - style.SetFieldRolloverTextColor(aText); - style.SetWindowTextColor(aText); - style.SetToolTextColor(aText); - - // Base - style.SetFieldColor(aBase); - style.SetWindowColor(aBase); - style.SetActiveTabColor(aBase); - style.SetAlternatingRowColor(toColor(pal.color(QPalette::Active, QPalette::AlternateBase))); - - // Buttons - style.SetDefaultButtonTextColor(aButn); - style.SetButtonTextColor(aButn); - style.SetDefaultActionButtonTextColor(aButn); - style.SetActionButtonTextColor(aButn); - style.SetFlatButtonTextColor(aButn); - style.SetDefaultButtonRolloverTextColor(aButn); - style.SetButtonRolloverTextColor(aButn); - style.SetDefaultActionButtonRolloverTextColor(aButn); - style.SetActionButtonRolloverTextColor(aButn); - style.SetFlatButtonRolloverTextColor(aButn); - style.SetDefaultButtonPressedRolloverTextColor(aButn); - style.SetButtonPressedRolloverTextColor(aButn); - style.SetDefaultActionButtonPressedRolloverTextColor(aButn); - style.SetActionButtonPressedRolloverTextColor(aButn); - style.SetFlatButtonPressedRolloverTextColor(aButn); - - // Tabs - style.SetTabTextColor(aButn); - style.SetTabRolloverTextColor(aButn); - style.SetTabHighlightTextColor(aButn); - - // Disable color - style.SetDisableColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText))); - - // Background - style.BatchSetBackgrounds(aBack); - style.SetInactiveTabColor(aBack); - - // Workspace - style.SetWorkspaceColor(aMid); - - // Selection - style.SetHighlightColor(aHigh); - style.SetHighlightTextColor(aHighText); - style.SetActiveColor(aHigh); - style.SetActiveTextColor(aHighText); - - // Links - style.SetLinkColor(aLink); - style.SetVisitedLinkColor(aVisitedLink); - - // Tooltip - style.SetHelpColor(toColor(QToolTip::palette().color(QPalette::Active, QPalette::ToolTipBase))); - style.SetHelpTextColor( - toColor(QToolTip::palette().color(QPalette::Active, QPalette::ToolTipText))); - - const int flash_time = QApplication::cursorFlashTime(); - style.SetCursorBlinkTime(flash_time != 0 ? flash_time / 2 : STYLE_CURSOR_NOBLINKTIME); - - // Menu - std::unique_ptr<QMenuBar> pMenuBar = std::make_unique<QMenuBar>(); - QPalette qMenuCG = pMenuBar->palette(); - - // Menu text and background color, theme specific - Color aMenuFore = toColor(qMenuCG.color(QPalette::WindowText)); - Color aMenuBack = toColor(qMenuCG.color(QPalette::Window)); - - style.SetMenuTextColor(aMenuFore); - style.SetMenuBarTextColor(style.GetPersonaMenuBarTextColor().value_or(aMenuFore)); - style.SetMenuColor(aMenuBack); - style.SetMenuBarColor(aMenuBack); - style.SetMenuHighlightColor(toColor(qMenuCG.color(QPalette::Highlight))); - style.SetMenuHighlightTextColor(toColor(qMenuCG.color(QPalette::HighlightedText))); - - // set special menubar highlight text color - if (QApplication::style()->inherits("HighContrastStyle")) - ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor - = toColor(qMenuCG.color(QPalette::HighlightedText)); - else - ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore; - - // set menubar rollover color - if (pMenuBar->style()->styleHint(QStyle::SH_MenuBar_MouseTracking)) - { - style.SetMenuBarRolloverColor(toColor(qMenuCG.color(QPalette::Highlight))); - style.SetMenuBarRolloverTextColor(ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor); - } - else - { - style.SetMenuBarRolloverColor(aMenuBack); - style.SetMenuBarRolloverTextColor(aMenuFore); - } - style.SetMenuBarHighlightTextColor(style.GetMenuHighlightTextColor()); - - // Icon theme - style.SetPreferredIconTheme(toOUString(QIcon::themeName())); - - // Scroll bar size - style.SetScrollBarSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent)); - style.SetMinThumbSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarSliderMin)); - - // These colors are used for the ruler text and marks - style.SetShadowColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText))); - style.SetDarkShadowColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText))); - - rSettings.SetStyleSettings(style); -} - -void QtFrame::Beep() { QApplication::beep(); } - -SalFrame::SalPointerState QtFrame::GetPointerState() -{ - SalPointerState aState; - aState.maPos = toPoint(QCursor::pos() * devicePixelRatioF()); - aState.maPos.Move(-maGeometry.nX, -maGeometry.nY); - aState.mnState = GetMouseModCode(QGuiApplication::mouseButtons()) - | GetKeyModCode(QGuiApplication::keyboardModifiers()); - return aState; -} - -KeyIndicatorState QtFrame::GetIndicatorState() { return KeyIndicatorState(); } - -void QtFrame::SimulateKeyPress(sal_uInt16 nKeyCode) -{ - SAL_WARN("vcl.qt5", "missing simulate keypress " << nKeyCode); -} - -void QtFrame::SetParent(SalFrame* pNewParent) { m_pParent = static_cast<QtFrame*>(pNewParent); } - -void QtFrame::SetPluginParent(SystemParentData* /*pNewParent*/) -{ - //FIXME: no SetPluginParent impl. for qt5 -} - -void QtFrame::ResetClipRegion() { m_bNullRegion = true; } - -void QtFrame::BeginSetClipRegion(sal_uInt32) -{ - m_aRegion = QRegion(QRect(QPoint(0, 0), m_pQWidget->size())); -} - -void QtFrame::UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) -{ - m_aRegion - = m_aRegion.united(scaledQRect(QRect(nX, nY, nWidth, nHeight), 1 / devicePixelRatioF())); -} - -void QtFrame::EndSetClipRegion() { m_bNullRegion = false; } - -void QtFrame::SetScreenNumber(unsigned int nScreen) -{ - if (!isWindow()) - return; - - QWindow* const pWindow = windowHandle(); - if (!pWindow) - return; - - QList<QScreen*> screens = QApplication::screens(); - if (static_cast<int>(nScreen) < screens.size() || m_bFullScreenSpanAll) - { - QRect screenGeo; - - if (!m_bFullScreenSpanAll) - { - screenGeo = QGuiApplication::screens().at(nScreen)->geometry(); - pWindow->setScreen(QApplication::screens()[nScreen]); - } - else // special case: fullscreen over all available screens - { - assert(m_bFullScreen); - // left-most screen -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - QScreen* pScreen = QGuiApplication::screenAt(QPoint(0, 0)); -#else - // QGuiApplication::screenAt was added in Qt 5.10, use deprecated QDesktopWidget - int nLeftScreen = QApplication::desktop()->screenNumber(QPoint(0, 0)); - QScreen* pScreen = QGuiApplication::screens()[nLeftScreen]; -#endif - // entire virtual desktop - screenGeo = pScreen->availableVirtualGeometry(); - pWindow->setScreen(pScreen); - pWindow->setGeometry(screenGeo); - nScreen = screenNumber(pScreen); - } - - // setScreen by itself has no effect, explicitly move the widget to - // the new screen - asChild()->move(screenGeo.topLeft()); - } - else - { - // index outta bounds, use primary screen - QScreen* primaryScreen = QApplication::primaryScreen(); - pWindow->setScreen(primaryScreen); - nScreen = static_cast<sal_uInt32>(screenNumber(primaryScreen)); - } - - maGeometry.nDisplayScreenNumber = nScreen; -} - -void QtFrame::SetApplicationID(const OUString& rWMClass) -{ -#if QT5_USING_X11 - if (QGuiApplication::platformName() != "xcb" || !m_pTopLevel) - return; - - OString aResClass = OUStringToOString(rWMClass, RTL_TEXTENCODING_ASCII_US); - const char* pResClass - = !aResClass.isEmpty() ? aResClass.getStr() : SalGenericSystem::getFrameClassName(); - OString aResName = SalGenericSystem::getFrameResName(); - - // the WM_CLASS data consists of two concatenated cstrings, including the terminating '\0' chars - const uint32_t data_len = aResName.getLength() + 1 + strlen(pResClass) + 1; - char* data = new char[data_len]; - memcpy(data, aResName.getStr(), aResName.getLength() + 1); - memcpy(data + aResName.getLength() + 1, pResClass, strlen(pResClass) + 1); - - xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, m_pTopLevel->winId(), - XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, data_len, data); - delete[] data; -#else - (void)rWMClass; -#endif -} - -// Drag'n'drop foo - -void QtFrame::registerDragSource(QtDragSource* pDragSource) -{ - assert(!m_pDragSource); - m_pDragSource = pDragSource; -} - -void QtFrame::deregisterDragSource(QtDragSource const* pDragSource) -{ - assert(m_pDragSource == pDragSource); - (void)pDragSource; - m_pDragSource = nullptr; -} - -void QtFrame::registerDropTarget(QtDropTarget* pDropTarget) -{ - assert(!m_pDropTarget); - m_pDropTarget = pDropTarget; - m_pQWidget->setAcceptDrops(true); -} - -void QtFrame::deregisterDropTarget(QtDropTarget const* pDropTarget) -{ - assert(m_pDropTarget == pDropTarget); - (void)pDropTarget; - m_pDropTarget = nullptr; -} - -static css::uno::Reference<css::datatransfer::XTransferable> -lcl_getXTransferable(const QMimeData* pMimeData) -{ - css::uno::Reference<css::datatransfer::XTransferable> xTransferable; - const QtMimeData* pQtMimeData = dynamic_cast<const QtMimeData*>(pMimeData); - if (!pQtMimeData) - xTransferable = new QtDnDTransferable(pMimeData); - else - xTransferable = pQtMimeData->xTransferable(); - return xTransferable; -} - -static sal_Int8 lcl_getUserDropAction(const QDropEvent* pEvent, const sal_Int8 nSourceActions, - const QMimeData* pMimeData) -{ - // we completely ignore all proposals by the Qt event, as they don't - // match at all with the preferred LO DnD actions. - - // check the key modifiers to detect a user-overridden DnD action - const Qt::KeyboardModifiers eKeyMod = pEvent->keyboardModifiers(); - sal_Int8 nUserDropAction = 0; - if ((eKeyMod & Qt::ShiftModifier) && !(eKeyMod & Qt::ControlModifier)) - nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_MOVE; - else if ((eKeyMod & Qt::ControlModifier) && !(eKeyMod & Qt::ShiftModifier)) - nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_COPY; - else if ((eKeyMod & Qt::ShiftModifier) && (eKeyMod & Qt::ControlModifier)) - nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_LINK; - nUserDropAction &= nSourceActions; - - // select the default DnD action, if there isn't a user preference - if (0 == nUserDropAction) - { - // default LO internal action is move, but default external action is copy - nUserDropAction = dynamic_cast<const QtMimeData*>(pMimeData) - ? css::datatransfer::dnd::DNDConstants::ACTION_MOVE - : css::datatransfer::dnd::DNDConstants::ACTION_COPY; - nUserDropAction &= nSourceActions; - - // if the default doesn't match any allowed source action, fall back to the - // preferred of all allowed source actions - if (0 == nUserDropAction) - nUserDropAction = toVclDropAction(getPreferredDropAction(nSourceActions)); - - // this is "our" preference, but actually we would even prefer any default, - // if there is any - nUserDropAction |= css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT; - } - return nUserDropAction; -} - -void QtFrame::handleDragMove(QDragMoveEvent* pEvent) -{ - assert(m_pDropTarget); - - // prepare our suggested drop action for the drop target - const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions()); - const QMimeData* pMimeData = pEvent->mimeData(); - const sal_Int8 nUserDropAction = lcl_getUserDropAction(pEvent, nSourceActions, pMimeData); - const Point aPos = toPoint(pEvent->pos() * devicePixelRatioF()); - - css::datatransfer::dnd::DropTargetDragEnterEvent aEvent; - aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget); - aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDragContext*>(m_pDropTarget); - aEvent.LocationX = aPos.X(); - aEvent.LocationY = aPos.Y(); - aEvent.DropAction = nUserDropAction; - aEvent.SourceActions = nSourceActions; - - // ask the drop target to accept our drop action - if (!m_bInDrag) - { - aEvent.SupportedDataFlavors = lcl_getXTransferable(pMimeData)->getTransferDataFlavors(); - m_pDropTarget->fire_dragEnter(aEvent); - m_bInDrag = true; - } - else - m_pDropTarget->fire_dragOver(aEvent); - - // the drop target accepted our drop action => inform Qt - if (m_pDropTarget->proposedDropAction() != 0) - { - pEvent->setDropAction(getPreferredDropAction(m_pDropTarget->proposedDropAction())); - pEvent->accept(); - } - else // or maybe someone else likes it? - pEvent->ignore(); -} - -void QtFrame::handleDrop(QDropEvent* pEvent) -{ - assert(m_pDropTarget); - - // prepare our suggested drop action for the drop target - const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions()); - const sal_Int8 nUserDropAction - = lcl_getUserDropAction(pEvent, nSourceActions, pEvent->mimeData()); - const Point aPos = toPoint(pEvent->pos() * devicePixelRatioF()); - - css::datatransfer::dnd::DropTargetDropEvent aEvent; - aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget); - aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDropContext*>(m_pDropTarget); - aEvent.LocationX = aPos.X(); - aEvent.LocationY = aPos.Y(); - aEvent.SourceActions = nSourceActions; - aEvent.DropAction = nUserDropAction; - aEvent.Transferable = lcl_getXTransferable(pEvent->mimeData()); - - // ask the drop target to accept our drop action - m_pDropTarget->fire_drop(aEvent); - m_bInDrag = false; - - const bool bDropSuccessful = m_pDropTarget->dropSuccessful(); - const sal_Int8 nDropAction = m_pDropTarget->proposedDropAction(); - - // inform the drag source of the drag-origin frame of the drop result - if (pEvent->source()) - { - QtWidget* pWidget = dynamic_cast<QtWidget*>(pEvent->source()); - assert(pWidget); // AFAIK there shouldn't be any non-Qt5Widget as source in LO itself - if (pWidget) - pWidget->frame().m_pDragSource->fire_dragEnd(nDropAction, bDropSuccessful); - } - - // the drop target accepted our drop action => inform Qt - if (bDropSuccessful) - { - pEvent->setDropAction(getPreferredDropAction(nDropAction)); - pEvent->accept(); - } - else // or maybe someone else likes it? - pEvent->ignore(); -} - -void QtFrame::handleDragLeave() -{ - css::datatransfer::dnd::DropTargetEvent aEvent; - aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget); - m_pDropTarget->fire_dragExit(aEvent); - m_bInDrag = false; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics.cxx b/vcl/qt5/Qt5Graphics.cxx deleted file mode 100644 index 1e6197c4fa5d..000000000000 --- a/vcl/qt5/Qt5Graphics.cxx +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Graphics.hxx> - -#include <Qt5Data.hxx> -#include <Qt5Font.hxx> -#include <Qt5Frame.hxx> -#include <Qt5Graphics_Controls.hxx> -#include <Qt5Painter.hxx> - -#include <QtGui/QImage> -#include <QtGui/QPainter> -#include <QtWidgets/QPushButton> -#include <QtWidgets/QWidget> - -QtGraphics::QtGraphics( QtFrame *pFrame, QImage *pQImage ) - : m_pFrame( pFrame ) - , m_pTextStyle{ nullptr, } - , m_aTextColor( 0x00, 0x00, 0x00 ) -{ - m_pBackend = std::make_unique<QtGraphicsBackend>(m_pFrame, pQImage); - - if (!initWidgetDrawBackends(false)) - { - if (!QtData::noNativeControls()) - m_pWidgetDraw.reset(new QtGraphics_Controls(*this)); - } - if (m_pFrame) - setDevicePixelRatioF(m_pFrame->devicePixelRatioF()); -} - -QtGraphics::~QtGraphics() { ReleaseFonts(); } - -void QtGraphics::ChangeQImage(QImage* pQImage) -{ - m_pBackend->setQImage(pQImage); - m_pBackend->ResetClipRegion(); -} - -SalGraphicsImpl* QtGraphics::GetImpl() const { return m_pBackend.get(); } - -SystemGraphicsData QtGraphics::GetGraphicsData() const { return SystemGraphicsData(); } - -#if ENABLE_CAIRO_CANVAS - -bool QtGraphics::SupportsCairo() const { return false; } - -cairo::SurfaceSharedPtr -QtGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& /*rSurface*/) const -{ - return nullptr; -} - -cairo::SurfaceSharedPtr QtGraphics::CreateSurface(const OutputDevice& /*rRefDevice*/, int /*x*/, - int /*y*/, int /*width*/, int /*height*/) const -{ - return nullptr; -} - -cairo::SurfaceSharedPtr QtGraphics::CreateBitmapSurface(const OutputDevice& /*rRefDevice*/, - const BitmapSystemData& /*rData*/, - const Size& /*rSize*/) const -{ - return nullptr; -} - -css::uno::Any QtGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*rSurface*/, - const basegfx::B2ISize& /*rSize*/) const -{ - return css::uno::Any(); -} - -#endif - -void QtGraphics::handleDamage(const tools::Rectangle& rDamagedRegion) -{ - assert(m_pWidgetDraw); - assert(dynamic_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())); - assert(!rDamagedRegion.IsEmpty()); - - QImage* pImage = static_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())->getImage(); - QImage blit(*pImage); - blit.setDevicePixelRatio(1); - QtPainter aPainter(*m_pBackend); - aPainter.drawImage(QPoint(rDamagedRegion.Left(), rDamagedRegion.Top()), blit); - aPainter.update(toQRect(rDamagedRegion)); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics_Controls.cxx b/vcl/qt5/Qt5Graphics_Controls.cxx deleted file mode 100644 index 077b92e54422..000000000000 --- a/vcl/qt5/Qt5Graphics_Controls.cxx +++ /dev/null @@ -1,1134 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Graphics_Controls.hxx> - -#include <QtGui/QPainter> -#include <QtWidgets/QApplication> -#include <QtWidgets/QFrame> -#include <QtWidgets/QLabel> - -#include <Qt5Tools.hxx> -#include <Qt5GraphicsBase.hxx> -#include <vcl/decoview.hxx> - -/** - Conversion function between VCL ControlState together with - ImplControlValue and Qt state flags. - @param nControlState State of the widget (default, focused, ...) in Native Widget Framework. - @param aValue Value held by the widget (on, off, ...) -*/ -static QStyle::State vclStateValue2StateFlag(ControlState nControlState, - const ImplControlValue& aValue) -{ - QStyle::State nState - = ((nControlState & ControlState::ENABLED) ? QStyle::State_Enabled : QStyle::State_None) - | ((nControlState & ControlState::FOCUSED) ? QStyle::State_HasFocus : QStyle::State_None) - | ((nControlState & ControlState::PRESSED) ? QStyle::State_Sunken : QStyle::State_None) - | ((nControlState & ControlState::SELECTED) ? QStyle::State_Selected : QStyle::State_None) - | ((nControlState & ControlState::ROLLOVER) ? QStyle::State_MouseOver - : QStyle::State_None); - - switch (aValue.getTristateVal()) - { - case ButtonValue::On: - nState |= QStyle::State_On; - break; - case ButtonValue::Off: - nState |= QStyle::State_Off; - break; - case ButtonValue::Mixed: - nState |= QStyle::State_NoChange; - break; - default: - break; - } - - return nState; -} - -static void lcl_ApplyBackgroundColorToStyleOption(QStyleOption& rOption, - const Color& rBackgroundColor) -{ - if (rBackgroundColor != COL_AUTO) - { - QColor aColor = toQColor(rBackgroundColor); - for (QPalette::ColorRole role : { QPalette::Window, QPalette::Button, QPalette::Base }) - rOption.palette.setColor(role, aColor); - } -} - -QtGraphics_Controls::QtGraphics_Controls(const QtGraphicsBase& rGraphics) - : m_rGraphics(rGraphics) -{ -} - -bool QtGraphics_Controls::isNativeControlSupported(ControlType type, ControlPart part) -{ - switch (type) - { - case ControlType::Tooltip: - case ControlType::Progress: - case ControlType::ListNode: - return (part == ControlPart::Entire); - - case ControlType::Radiobutton: - case ControlType::Checkbox: - return (part == ControlPart::Entire) || (part == ControlPart::Focus); - case ControlType::Pushbutton: - return (part == ControlPart::Entire); - - case ControlType::ListHeader: - return (part == ControlPart::Button); - - case ControlType::Menubar: - case ControlType::MenuPopup: - case ControlType::Editbox: - case ControlType::MultilineEditbox: - case ControlType::Combobox: - case ControlType::Toolbar: - case ControlType::Frame: - case ControlType::Scrollbar: - case ControlType::WindowBackground: - case ControlType::Fixedline: - return true; - - case ControlType::Listbox: - return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture); - - case ControlType::Spinbox: - return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture); - - case ControlType::Slider: - return (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea); - - case ControlType::TabItem: - case ControlType::TabPane: - return ((part == ControlPart::Entire) || part == ControlPart::TabPaneWithHeader); - - default: - break; - } - - return false; -} - -inline int QtGraphics_Controls::pixelMetric(QStyle::PixelMetric metric, const QStyleOption* option) -{ - return QApplication::style()->pixelMetric(metric, option); -} - -inline QSize QtGraphics_Controls::sizeFromContents(QStyle::ContentsType type, - const QStyleOption* option, - const QSize& contentsSize) -{ - return QApplication::style()->sizeFromContents(type, option, contentsSize); -} - -inline QRect QtGraphics_Controls::subControlRect(QStyle::ComplexControl control, - const QStyleOptionComplex* option, - QStyle::SubControl subControl) -{ - return QApplication::style()->subControlRect(control, option, subControl); -} - -inline QRect QtGraphics_Controls::subElementRect(QStyle::SubElement element, - const QStyleOption* option) -{ - return QApplication::style()->subElementRect(element, option); -} - -void QtGraphics_Controls::draw(QStyle::ControlElement element, QStyleOption& rOption, QImage* image, - const Color& rBackgroundColor, QStyle::State const state, QRect rect) -{ - const QRect& targetRect = !rect.isNull() ? rect : image->rect(); - - rOption.state |= state; - rOption.rect = downscale(targetRect); - - lcl_ApplyBackgroundColorToStyleOption(rOption, rBackgroundColor); - - QPainter painter(image); - QApplication::style()->drawControl(element, &rOption, &painter); -} - -void QtGraphics_Controls::draw(QStyle::PrimitiveElement element, QStyleOption& rOption, - QImage* image, const Color& rBackgroundColor, - QStyle::State const state, QRect rect) -{ - const QRect& targetRect = !rect.isNull() ? rect : image->rect(); - - rOption.state |= state; - rOption.rect = downscale(targetRect); - - lcl_ApplyBackgroundColorToStyleOption(rOption, rBackgroundColor); - - QPainter painter(image); - QApplication::style()->drawPrimitive(element, &rOption, &painter); -} - -void QtGraphics_Controls::draw(QStyle::ComplexControl element, QStyleOptionComplex& rOption, - QImage* image, const Color& rBackgroundColor, - QStyle::State const state) -{ - const QRect& targetRect = image->rect(); - - rOption.state |= state; - rOption.rect = downscale(targetRect); - - lcl_ApplyBackgroundColorToStyleOption(rOption, rBackgroundColor); - - QPainter painter(image); - QApplication::style()->drawComplexControl(element, &rOption, &painter); -} - -void QtGraphics_Controls::drawFrame(QStyle::PrimitiveElement element, QImage* image, - const Color& rBackgroundColor, QStyle::State const& state, - bool bClip, QStyle::PixelMetric eLineMetric) -{ - const int fw = pixelMetric(eLineMetric); - QStyleOptionFrame option; - option.frameShape = QFrame::StyledPanel; - option.state = QStyle::State_Sunken | state; - option.lineWidth = fw; - - QRect aRect = downscale(image->rect()); - option.rect = aRect; - - lcl_ApplyBackgroundColorToStyleOption(option, rBackgroundColor); - - QPainter painter(image); - if (bClip) - painter.setClipRegion(QRegion(aRect).subtracted(aRect.adjusted(fw, fw, -fw, -fw))); - QApplication::style()->drawPrimitive(element, &option, &painter); -} - -void QtGraphics_Controls::fillQStyleOptionTab(const ImplControlValue& value, QStyleOptionTab& sot) -{ - const TabitemValue& rValue = static_cast<const TabitemValue&>(value); - if (rValue.isFirst()) - sot.position = rValue.isLast() ? QStyleOptionTab::OnlyOneTab : QStyleOptionTab::Beginning; - else if (rValue.isLast()) - sot.position = rValue.isFirst() ? QStyleOptionTab::OnlyOneTab : QStyleOptionTab::End; - else - sot.position = QStyleOptionTab::Middle; -} - -void QtGraphics_Controls::fullQStyleOptionTabWidgetFrame(QStyleOptionTabWidgetFrame& option, - bool bDownscale) -{ - option.state = QStyle::State_Enabled; - option.rightCornerWidgetSize = QSize(0, 0); - option.leftCornerWidgetSize = QSize(0, 0); - int nLineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth); - option.lineWidth = bDownscale ? std::max(1, downscale(nLineWidth, Round::Ceil)) : nLineWidth; - option.midLineWidth = 0; - option.shape = QTabBar::RoundedNorth; -} - -bool QtGraphics_Controls::drawNativeControl(ControlType type, ControlPart part, - const tools::Rectangle& rControlRegion, - ControlState nControlState, - const ImplControlValue& value, const OUString&, - const Color& rBackgroundColor) -{ - bool nativeSupport = isNativeControlSupported(type, part); - if (!nativeSupport) - { - assert(!nativeSupport && "drawNativeControl called without native support!"); - return false; - } - - if (m_lastPopupRect.isValid() - && (type != ControlType::MenuPopup || part != ControlPart::MenuItem)) - m_lastPopupRect = QRect(); - - bool returnVal = true; - - QRect widgetRect = toQRect(rControlRegion); - - //if no image, or resized, make a new image - if (!m_image || m_image->size() != widgetRect.size()) - { - m_image.reset(new QImage(widgetRect.width(), widgetRect.height(), - QImage::Format_ARGB32_Premultiplied)); - m_image->setDevicePixelRatio(m_rGraphics.devicePixelRatioF()); - } - - // Default image color - just once - switch (type) - { - case ControlType::MenuPopup: - if (part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark) - { - // it is necessary to fill the background transparently first, as this - // is painted after menuitem highlight, otherwise there would be a grey area - m_image->fill(Qt::transparent); - break; - } - [[fallthrough]]; // QPalette::Window - case ControlType::Menubar: - case ControlType::WindowBackground: - m_image->fill(QApplication::palette().color(QPalette::Window).rgb()); - break; - case ControlType::Tooltip: - m_image->fill(QApplication::palette().color(QPalette::ToolTipBase).rgb()); - break; - case ControlType::Scrollbar: - if ((part == ControlPart::DrawBackgroundVert) - || (part == ControlPart::DrawBackgroundHorz)) - { - m_image->fill(QApplication::palette().color(QPalette::Window).rgb()); - break; - } - [[fallthrough]]; // Qt::transparent - default: - m_image->fill(Qt::transparent); - break; - } - - if (type == ControlType::Pushbutton) - { - const PushButtonValue& rPBValue = static_cast<const PushButtonValue&>(value); - assert(part == ControlPart::Entire); - QStyleOptionButton option; - if (nControlState & ControlState::DEFAULT) - option.features |= QStyleOptionButton::DefaultButton; - if (rPBValue.m_bFlatButton) - option.features |= QStyleOptionButton::Flat; - draw(QStyle::CE_PushButton, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::Menubar) - { - if (part == ControlPart::MenuItem) - { - QStyleOptionMenuItem option; - option.state = vclStateValue2StateFlag(nControlState, value); - if ((nControlState & ControlState::ROLLOVER) - && QApplication::style()->styleHint(QStyle::SH_MenuBar_MouseTracking)) - option.state |= QStyle::State_Selected; - - if (nControlState - & ControlState::SELECTED) // Passing State_Sunken is currently not documented. - option.state |= QStyle::State_Sunken; // But some kinds of QStyle interpret it. - - draw(QStyle::CE_MenuBarItem, option, m_image.get(), rBackgroundColor); - } - else if (part == ControlPart::Entire) - { - QStyleOptionMenuItem option; - draw(QStyle::CE_MenuBarEmptyArea, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else - { - returnVal = false; - } - } - else if (type == ControlType::MenuPopup) - { - assert(part == ControlPart::MenuItem ? m_lastPopupRect.isValid() - : !m_lastPopupRect.isValid()); - if (part == ControlPart::MenuItem) - { - QStyleOptionMenuItem option; - draw(QStyle::CE_MenuItem, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - // HACK: LO core first paints the entire popup and only then it paints menu items, - // but QMenu::paintEvent() paints popup frame after all items. That means highlighted - // items here would paint the highlight over the frame border. Since calls to ControlPart::MenuItem - // are always preceded by calls to ControlPart::Entire, just remember the size for the whole - // popup (otherwise not possible to get here) and draw the border afterwards. - QRect framerect(m_lastPopupRect.topLeft() - widgetRect.topLeft(), - widgetRect.size().expandedTo(m_lastPopupRect.size())); - QStyleOptionFrame frame; - draw(QStyle::PE_FrameMenu, frame, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value), framerect); - } - else if (part == ControlPart::Separator) - { - QStyleOptionMenuItem option; - option.menuItemType = QStyleOptionMenuItem::Separator; - // Painting the whole menu item area results in different background - // with at least Plastique style, so clip only to the separator itself - // (QSize( 2, 2 ) is hardcoded in Qt) - option.rect = m_image->rect(); - QSize size = sizeFromContents(QStyle::CT_MenuItem, &option, QSize(2, 2)); - QRect rect = m_image->rect(); - QPoint center = rect.center(); - rect.setHeight(size.height()); - rect.moveCenter(center); - option.state |= vclStateValue2StateFlag(nControlState, value); - option.rect = rect; - - QPainter painter(m_image.get()); - // don't paint over popup frame border (like the hack above, but here it can be simpler) - const int fw = pixelMetric(QStyle::PM_MenuPanelWidth); - painter.setClipRect(rect.adjusted(fw, 0, -fw, 0)); - QApplication::style()->drawControl(QStyle::CE_MenuItem, &option, &painter); - } - else if (part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark) - { - QStyleOptionMenuItem option; - option.checkType = (part == ControlPart::MenuItemCheckMark) - ? QStyleOptionMenuItem::NonExclusive - : QStyleOptionMenuItem::Exclusive; - option.checked = bool(nControlState & ControlState::PRESSED); - // widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt - // paints the whole menu item, so translate position (and it'll be clipped); - // it is also necessary to fill the background transparently first, as this - // is painted after menuitem highlight, otherwise there would be a grey area - assert(value.getType() == ControlType::MenuPopup); - const MenupopupValue* menuVal = static_cast<const MenupopupValue*>(&value); - QRect menuItemRect(toQRect(menuVal->maItemRect)); - QRect rect(menuItemRect.topLeft() - widgetRect.topLeft(), - widgetRect.size().expandedTo(menuItemRect.size())); - // checkboxes are always displayed next to images in menus, so are never centered - const int focus_size = pixelMetric(QStyle::PM_FocusFrameHMargin); - rect.moveTo(-focus_size, rect.y()); - draw(QStyle::CE_MenuItem, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState & ~ControlState::PRESSED, value), rect); - } - else if (part == ControlPart::Entire) - { - QStyleOptionMenuItem option; - option.state = vclStateValue2StateFlag(nControlState, value); - draw(QStyle::PE_PanelMenu, option, m_image.get(), rBackgroundColor); - // Try hard to get any frame! - QStyleOptionFrame frame; - draw(QStyle::PE_FrameMenu, frame, m_image.get(), rBackgroundColor); - draw(QStyle::PE_FrameWindow, frame, m_image.get(), rBackgroundColor); - m_lastPopupRect = widgetRect; - } - else - returnVal = false; - } - else if ((type == ControlType::Toolbar) && (part == ControlPart::Button)) - { - QStyleOptionToolButton option; - - option.arrowType = Qt::NoArrow; - option.subControls = QStyle::SC_ToolButton; - option.state = vclStateValue2StateFlag(nControlState, value); - option.state |= QStyle::State_Raised | QStyle::State_Enabled | QStyle::State_AutoRaise; - - draw(QStyle::CC_ToolButton, option, m_image.get(), rBackgroundColor); - } - else if ((type == ControlType::Toolbar) && (part == ControlPart::Entire)) - { - QStyleOptionToolBar option; - draw(QStyle::CE_ToolBar, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if ((type == ControlType::Toolbar) - && (part == ControlPart::ThumbVert || part == ControlPart::ThumbHorz)) - { - // reduce paint area only to the handle area - const int handleExtend = pixelMetric(QStyle::PM_ToolBarHandleExtent); - QStyleOption option; - QRect aRect = m_image->rect(); - if (part == ControlPart::ThumbVert) - { - aRect.setWidth(handleExtend); - option.state = QStyle::State_Horizontal; - } - else - aRect.setHeight(handleExtend); - draw(QStyle::PE_IndicatorToolBarHandle, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value), aRect); - } - else if (type == ControlType::Editbox || type == ControlType::MultilineEditbox) - { - drawFrame(QStyle::PE_FrameLineEdit, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value), false); - } - else if (type == ControlType::Combobox) - { - QStyleOptionComboBox option; - option.editable = true; - draw(QStyle::CC_ComboBox, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::Listbox) - { - QStyleOptionComboBox option; - option.editable = false; - switch (part) - { - case ControlPart::ListboxWindow: - drawFrame(QStyle::PE_Frame, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value), true, - QStyle::PM_ComboBoxFrameWidth); - break; - case ControlPart::SubEdit: - draw(QStyle::CE_ComboBoxLabel, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - break; - case ControlPart::Entire: - draw(QStyle::CC_ComboBox, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - break; - case ControlPart::ButtonDown: - option.subControls = QStyle::SC_ComboBoxArrow; - draw(QStyle::CC_ComboBox, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - break; - default: - returnVal = false; - break; - } - } - else if (type == ControlType::ListNode) - { - QStyleOption option; - option.state = vclStateValue2StateFlag(nControlState, value); - option.state |= QStyle::State_Item | QStyle::State_Children; - - if (value.getTristateVal() == ButtonValue::On) - option.state |= QStyle::State_Open; - - draw(QStyle::PE_IndicatorBranch, option, m_image.get(), rBackgroundColor); - } - else if (type == ControlType::ListHeader) - { - QStyleOptionHeader option; - draw(QStyle::CE_HeaderSection, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::Checkbox) - { - if (part == ControlPart::Entire) - { - QStyleOptionButton option; - // clear FOCUSED bit, focus is drawn separately - nControlState &= ~ControlState::FOCUSED; - draw(QStyle::CE_CheckBox, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (part == ControlPart::Focus) - { - QStyleOptionFocusRect option; - draw(QStyle::PE_FrameFocusRect, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - } - else if (type == ControlType::Scrollbar) - { - if ((part == ControlPart::DrawBackgroundVert) || (part == ControlPart::DrawBackgroundHorz)) - { - QStyleOptionSlider option; - assert(value.getType() == ControlType::Scrollbar); - const ScrollbarValue* sbVal = static_cast<const ScrollbarValue*>(&value); - - //if the scroll bar is active (aka not degenerate... allow for hover events) - if (sbVal->mnVisibleSize < sbVal->mnMax) - option.state = QStyle::State_MouseOver; - - bool horizontal = (part == ControlPart::DrawBackgroundHorz); //horizontal or vertical - option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; - if (horizontal) - option.state |= QStyle::State_Horizontal; - - // If the scrollbar has a mnMin == 0 and mnMax == 0 then mnVisibleSize is set to -1?! - // I don't know if a negative mnVisibleSize makes any sense, so just handle this case - // without crashing LO with a SIGFPE in the Qt library. - const tools::Long nVisibleSize - = (sbVal->mnMin == sbVal->mnMax) ? 0 : sbVal->mnVisibleSize; - - option.minimum = sbVal->mnMin; - option.maximum = sbVal->mnMax - nVisibleSize; - option.maximum = qMax(option.maximum, option.minimum); // bnc#619772 - option.sliderValue = sbVal->mnCur; - option.sliderPosition = sbVal->mnCur; - option.pageStep = nVisibleSize; - if (part == ControlPart::DrawBackgroundHorz) - option.upsideDown - = (QGuiApplication::isRightToLeft() - && sbVal->maButton1Rect.Left() < sbVal->maButton2Rect.Left()) - || (QGuiApplication::isLeftToRight() - && sbVal->maButton1Rect.Left() > sbVal->maButton2Rect.Left()); - - //setup the active control... always the slider - if (sbVal->mnThumbState & ControlState::ROLLOVER) - option.activeSubControls = QStyle::SC_ScrollBarSlider; - - draw(QStyle::CC_ScrollBar, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else - { - returnVal = false; - } - } - else if (type == ControlType::Spinbox) - { - QStyleOptionSpinBox option; - option.frame = true; - - // determine active control - if (value.getType() == ControlType::SpinButtons) - { - const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue*>(&value); - if (pSpinVal->mnUpperState & ControlState::PRESSED) - option.activeSubControls |= QStyle::SC_SpinBoxUp; - if (pSpinVal->mnLowerState & ControlState::PRESSED) - option.activeSubControls |= QStyle::SC_SpinBoxDown; - if (pSpinVal->mnUpperState & ControlState::ENABLED) - option.stepEnabled |= QAbstractSpinBox::StepUpEnabled; - if (pSpinVal->mnLowerState & ControlState::ENABLED) - option.stepEnabled |= QAbstractSpinBox::StepDownEnabled; - if (pSpinVal->mnUpperState & ControlState::ROLLOVER) - option.state = QStyle::State_MouseOver; - if (pSpinVal->mnLowerState & ControlState::ROLLOVER) - option.state = QStyle::State_MouseOver; - } - - draw(QStyle::CC_SpinBox, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::Radiobutton) - { - if (part == ControlPart::Entire) - { - QStyleOptionButton option; - // clear FOCUSED bit, focus is drawn separately - nControlState &= ~ControlState::FOCUSED; - draw(QStyle::CE_RadioButton, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (part == ControlPart::Focus) - { - QStyleOptionFocusRect option; - draw(QStyle::PE_FrameFocusRect, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - } - else if (type == ControlType::Tooltip) - { - QStyleOption option; - draw(QStyle::PE_PanelTipLabel, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::Frame) - { - drawFrame(QStyle::PE_Frame, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::WindowBackground) - { - // Nothing to do - see "Default image color" switch ^^ - } - else if (type == ControlType::Fixedline) - { - QStyleOptionMenuItem option; - option.menuItemType = QStyleOptionMenuItem::Separator; - option.state = vclStateValue2StateFlag(nControlState, value); - option.state |= QStyle::State_Item; - - draw(QStyle::CE_MenuItem, option, m_image.get(), rBackgroundColor); - } - else if (type == ControlType::Slider - && (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea)) - { - assert(value.getType() == ControlType::Slider); - const SliderValue* slVal = static_cast<const SliderValue*>(&value); - QStyleOptionSlider option; - - option.state = vclStateValue2StateFlag(nControlState, value); - option.maximum = slVal->mnMax; - option.minimum = slVal->mnMin; - option.sliderPosition = option.sliderValue = slVal->mnCur; - bool horizontal = (part == ControlPart::TrackHorzArea); //horizontal or vertical - option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; - if (horizontal) - option.state |= QStyle::State_Horizontal; - - draw(QStyle::CC_Slider, option, m_image.get(), rBackgroundColor); - } - else if (type == ControlType::Progress && part == ControlPart::Entire) - { - QStyleOptionProgressBar option; - option.minimum = 0; - option.maximum = widgetRect.width(); - option.progress = value.getNumericVal(); - - draw(QStyle::CE_ProgressBar, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::TabItem && part == ControlPart::Entire) - { - QStyleOptionTab sot; - fillQStyleOptionTab(value, sot); - draw(QStyle::CE_TabBarTabShape, sot, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value)); - } - else if (type == ControlType::TabPane && part == ControlPart::Entire) - { - const TabPaneValue& rValue = static_cast<const TabPaneValue&>(value); - - // get the overlap size for the tabs, so they will overlap the frame - QStyleOptionTab tabOverlap; - tabOverlap.shape = QTabBar::RoundedNorth; - TabPaneValue::m_nOverlap = pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap); - - QStyleOptionTabWidgetFrame option; - fullQStyleOptionTabWidgetFrame(option, false); - option.tabBarRect = toQRect(rValue.m_aTabHeaderRect); - option.selectedTabRect - = rValue.m_aSelectedTabRect.IsEmpty() ? QRect() : toQRect(rValue.m_aSelectedTabRect); - option.tabBarSize = toQSize(rValue.m_aTabHeaderRect.GetSize()); - option.rect = m_image->rect(); - QRect aRect = subElementRect(QStyle::SE_TabWidgetTabPane, &option); - draw(QStyle::PE_FrameTabWidget, option, m_image.get(), rBackgroundColor, - vclStateValue2StateFlag(nControlState, value), aRect); - } - else - { - returnVal = false; - } - - return returnVal; -} - -bool QtGraphics_Controls::getNativeControlRegion(ControlType type, ControlPart part, - const tools::Rectangle& controlRegion, - ControlState controlState, - const ImplControlValue& val, const OUString&, - tools::Rectangle& nativeBoundingRegion, - tools::Rectangle& nativeContentRegion) -{ - bool retVal = false; - - QRect boundingRect = toQRect(controlRegion); - QRect contentRect = boundingRect; - QStyleOptionComplex styleOption; - - switch (type) - { - // Metrics of the push button - case ControlType::Pushbutton: - if (part == ControlPart::Entire) - { - styleOption.state = vclStateValue2StateFlag(controlState, val); - - if (controlState & ControlState::DEFAULT) - { - int size = upscale(pixelMetric(QStyle::PM_ButtonDefaultIndicator, &styleOption), - Round::Ceil); - boundingRect.adjust(-size, -size, size, size); - retVal = true; - } - } - break; - case ControlType::Editbox: - case ControlType::MultilineEditbox: - { - // we have to get stable borders, otherwise layout loops. - // so we simply only scale the detected borders. - QStyleOptionFrame fo; - fo.frameShape = QFrame::StyledPanel; - fo.state = QStyle::State_Sunken; - fo.lineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth); - fo.rect = downscale(contentRect); - fo.rect.setSize(sizeFromContents(QStyle::CT_LineEdit, &fo, fo.rect.size())); - QRect aSubRect = subElementRect(QStyle::SE_LineEditContents, &fo); - - // VCL tests borders with small defaults before layout, where Qt returns no sub-rect, - // so this gets us at least some frame. - int nLine = upscale(fo.lineWidth, Round::Ceil); - int nLeft = qMin(-nLine, upscale(fo.rect.left() - aSubRect.left(), Round::Floor)); - int nTop = qMin(-nLine, upscale(fo.rect.top() - aSubRect.top(), Round::Floor)); - int nRight = qMax(nLine, upscale(fo.rect.right() - aSubRect.right(), Round::Ceil)); - int nBottom = qMax(nLine, upscale(fo.rect.bottom() - aSubRect.bottom(), Round::Ceil)); - boundingRect.adjust(nLeft, nTop, nRight, nBottom); - retVal = true; - break; - } - case ControlType::Checkbox: - if (part == ControlPart::Entire) - { - styleOption.state = vclStateValue2StateFlag(controlState, val); - - int nWidth = pixelMetric(QStyle::PM_IndicatorWidth, &styleOption); - int nHeight = pixelMetric(QStyle::PM_IndicatorHeight, &styleOption); - contentRect.setSize(upscale(QSize(nWidth, nHeight), Round::Ceil)); - - int nHMargin = pixelMetric(QStyle::PM_FocusFrameHMargin, &styleOption); - int nVMargin = pixelMetric(QStyle::PM_FocusFrameVMargin, &styleOption); - contentRect.adjust(0, 0, 2 * upscale(nHMargin, Round::Ceil), - 2 * upscale(nVMargin, Round::Ceil)); - - boundingRect = contentRect; - retVal = true; - } - break; - case ControlType::Combobox: - case ControlType::Listbox: - { - QStyleOptionComboBox cbo; - - cbo.rect = downscale(QRect(0, 0, contentRect.width(), contentRect.height())); - cbo.state = vclStateValue2StateFlag(controlState, val); - - switch (part) - { - case ControlPart::Entire: - { - // find out the minimum size that should be used - // assume contents is a text line - QSize aContentSize = downscale(contentRect.size(), Round::Ceil); - QFontMetrics aFontMetrics(QApplication::font()); - aContentSize.setHeight(aFontMetrics.height()); - QSize aMinSize = upscale( - sizeFromContents(QStyle::CT_ComboBox, &cbo, aContentSize), Round::Ceil); - if (aMinSize.height() > contentRect.height()) - contentRect.setHeight(aMinSize.height()); - boundingRect = contentRect; - retVal = true; - break; - } - case ControlPart::ButtonDown: - { - contentRect = upscale( - subControlRect(QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxArrow)); - contentRect.translate(boundingRect.left(), boundingRect.top()); - retVal = true; - break; - } - case ControlPart::SubEdit: - { - contentRect = upscale( - subControlRect(QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField)); - contentRect.translate(boundingRect.left(), boundingRect.top()); - retVal = true; - break; - } - default: - break; - } - break; - } - case ControlType::Spinbox: - { - QStyleOptionSpinBox sbo; - sbo.frame = true; - - sbo.rect = downscale(QRect(0, 0, contentRect.width(), contentRect.height())); - sbo.state = vclStateValue2StateFlag(controlState, val); - - switch (part) - { - case ControlPart::Entire: - { - QSize aContentSize = downscale(contentRect.size(), Round::Ceil); - QFontMetrics aFontMetrics(QApplication::font()); - aContentSize.setHeight(aFontMetrics.height()); - QSize aMinSize = upscale( - sizeFromContents(QStyle::CT_SpinBox, &sbo, aContentSize), Round::Ceil); - if (aMinSize.height() > contentRect.height()) - contentRect.setHeight(aMinSize.height()); - boundingRect = contentRect; - retVal = true; - break; - } - case ControlPart::ButtonUp: - contentRect - = upscale(subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp)); - contentRect.translate(boundingRect.left(), boundingRect.top()); - retVal = true; - break; - case ControlPart::ButtonDown: - contentRect - = upscale(subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown)); - contentRect.translate(boundingRect.left(), boundingRect.top()); - retVal = true; - break; - case ControlPart::SubEdit: - contentRect = upscale( - subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField)); - contentRect.translate(boundingRect.left(), boundingRect.top()); - retVal = true; - break; - default: - break; - } - break; - } - case ControlType::MenuPopup: - { - int h, w; - switch (part) - { - case ControlPart::MenuItemCheckMark: - h = upscale(pixelMetric(QStyle::PM_IndicatorHeight), Round::Floor); - w = upscale(pixelMetric(QStyle::PM_IndicatorWidth), Round::Floor); - retVal = true; - break; - case ControlPart::MenuItemRadioMark: - h = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorHeight), Round::Floor); - w = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorWidth), Round::Floor); - retVal = true; - break; - default: - break; - } - if (retVal) - { - contentRect = QRect(0, 0, w, h); - boundingRect = contentRect; - } - break; - } - case ControlType::Frame: - { - if (part == ControlPart::Border) - { - int nFrameWidth = upscale(pixelMetric(QStyle::PM_DefaultFrameWidth), Round::Ceil); - contentRect.adjust(nFrameWidth, nFrameWidth, -nFrameWidth, -nFrameWidth); - retVal = true; - } - break; - } - case ControlType::Radiobutton: - { - const int h = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorHeight), Round::Ceil); - const int w = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorWidth), Round::Ceil); - - contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h); - int nHMargin = pixelMetric(QStyle::PM_FocusFrameHMargin, &styleOption); - int nVMargin = pixelMetric(QStyle::PM_FocusFrameVMargin, &styleOption); - contentRect.adjust(0, 0, upscale(2 * nHMargin, Round::Ceil), - upscale(2 * nVMargin, Round::Ceil)); - boundingRect = contentRect; - - retVal = true; - break; - } - case ControlType::Slider: - { - const int w = upscale(pixelMetric(QStyle::PM_SliderLength), Round::Ceil); - if (part == ControlPart::ThumbHorz) - { - contentRect - = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height()); - boundingRect = contentRect; - retVal = true; - } - else if (part == ControlPart::ThumbVert) - { - contentRect - = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w); - boundingRect = contentRect; - retVal = true; - } - break; - } - case ControlType::Toolbar: - { - const int nWorH = upscale(pixelMetric(QStyle::PM_ToolBarHandleExtent), Round::Ceil); - if (part == ControlPart::ThumbHorz) - { - contentRect - = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), nWorH); - boundingRect = contentRect; - retVal = true; - } - else if (part == ControlPart::ThumbVert) - { - contentRect - = QRect(boundingRect.left(), boundingRect.top(), nWorH, boundingRect.height()); - boundingRect = contentRect; - retVal = true; - } - else if (part == ControlPart::Button) - { - QStyleOptionToolButton option; - option.arrowType = Qt::NoArrow; - option.features = QStyleOptionToolButton::None; - option.rect = downscale(QRect({ 0, 0 }, contentRect.size())); - contentRect = upscale( - subControlRect(QStyle::CC_ToolButton, &option, QStyle::SC_ToolButton)); - boundingRect = contentRect; - retVal = true; - } - break; - } - case ControlType::Scrollbar: - { - // core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(), - // for the rest also provide the track area (i.e. area not taken by buttons) - if (part == ControlPart::TrackVertArea || part == ControlPart::TrackHorzArea) - { - QStyleOptionSlider option; - bool horizontal = (part == ControlPart::TrackHorzArea); //horizontal or vertical - option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; - if (horizontal) - option.state |= QStyle::State_Horizontal; - // getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper - // subclass), so use random sensible values (doesn't matter anyway, as the wanted - // geometry here depends only on button sizes) - option.maximum = 10; - option.minimum = 0; - option.sliderPosition = option.sliderValue = 4; - option.pageStep = 2; - // Adjust coordinates to make the widget appear to be at (0,0), i.e. make - // widget and screen coordinates the same. QStyle functions should use screen - // coordinates but at least QPlastiqueStyle::subControlRect() is buggy - // and sometimes uses widget coordinates. - option.rect = downscale(QRect({ 0, 0 }, contentRect.size())); - contentRect = upscale( - subControlRect(QStyle::CC_ScrollBar, &option, QStyle::SC_ScrollBarGroove)); - contentRect.translate(boundingRect.left() - - (contentRect.width() - boundingRect.width()), - boundingRect.top()); - boundingRect = contentRect; - retVal = true; - } - break; - } - case ControlType::TabItem: - { - QStyleOptionTab sot; - fillQStyleOptionTab(val, sot); - QSize aMinSize = upscale(sizeFromContents(QStyle::CT_TabBarTab, &sot, - downscale(contentRect.size(), Round::Ceil)), - Round::Ceil); - contentRect.setSize(aMinSize); - boundingRect = contentRect; - retVal = true; - break; - } - case ControlType::TabPane: - { - const TabPaneValue& rValue = static_cast<const TabPaneValue&>(val); - QStyleOptionTabWidgetFrame sotwf; - fullQStyleOptionTabWidgetFrame(sotwf, true); - QSize contentSize( - std::max(rValue.m_aTabHeaderRect.GetWidth(), controlRegion.GetWidth()), - rValue.m_aTabHeaderRect.GetHeight() + controlRegion.GetHeight()); - QSize aMinSize = upscale( - sizeFromContents(QStyle::CT_TabWidget, &sotwf, downscale(contentSize, Round::Ceil)), - Round::Ceil); - contentRect.setSize(aMinSize); - boundingRect = contentRect; - retVal = true; - break; - } - default: - break; - } - if (retVal) - { - nativeBoundingRegion = toRectangle(boundingRect); - nativeContentRegion = toRectangle(contentRect); - } - - return retVal; -} - -/** Test whether the position is in the native widget. - If the return value is true, bIsInside contains information whether - aPos was or was not inside the native widget specified by the - nType/nPart combination. -*/ -bool QtGraphics_Controls::hitTestNativeControl(ControlType nType, ControlPart nPart, - const tools::Rectangle& rControlRegion, - const Point& rPos, bool& rIsInside) -{ - if (nType == ControlType::Scrollbar) - { - if (nPart != ControlPart::ButtonUp && nPart != ControlPart::ButtonDown - && nPart != ControlPart::ButtonLeft && nPart != ControlPart::ButtonRight) - { // we adjust only for buttons (because some scrollbars have 3 buttons, - // and LO core doesn't handle such scrollbars well) - return false; - } - rIsInside = false; - bool bHorizontal = (nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight); - QRect rect = toQRect(rControlRegion); - QPoint pos(rPos.X(), rPos.Y()); - // Adjust coordinates to make the widget appear to be at (0,0), i.e. make - // widget and screen coordinates the same. QStyle functions should use screen - // coordinates but at least QPlastiqueStyle::subControlRect() is buggy - // and sometimes uses widget coordinates. - pos -= rect.topLeft(); - rect.moveTo(0, 0); - QStyleOptionSlider options; - options.orientation = bHorizontal ? Qt::Horizontal : Qt::Vertical; - if (bHorizontal) - options.state |= QStyle::State_Horizontal; - options.rect = rect; - // some random sensible values, since we call this code only for scrollbar buttons, - // the slider position does not exactly matter - options.maximum = 10; - options.minimum = 0; - options.sliderPosition = options.sliderValue = 4; - options.pageStep = 2; - QStyle::SubControl control - = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, &options, pos); - if (nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonLeft) - rIsInside = (control == QStyle::SC_ScrollBarSubLine); - else // DOWN, RIGHT - rIsInside = (control == QStyle::SC_ScrollBarAddLine); - return true; - } - return false; -} - -inline int QtGraphics_Controls::downscale(int size, Round eRound) -{ - return static_cast<int>(eRound == Round::Ceil ? ceil(size / m_rGraphics.devicePixelRatioF()) - : floor(size / m_rGraphics.devicePixelRatioF())); -} - -inline int QtGraphics_Controls::upscale(int size, Round eRound) -{ - return static_cast<int>(eRound == Round::Ceil ? ceil(size * m_rGraphics.devicePixelRatioF()) - : floor(size * m_rGraphics.devicePixelRatioF())); -} - -inline QRect QtGraphics_Controls::downscale(const QRect& rect) -{ - return QRect(downscale(rect.x(), Round::Floor), downscale(rect.y(), Round::Floor), - downscale(rect.width(), Round::Ceil), downscale(rect.height(), Round::Ceil)); -} - -inline QRect QtGraphics_Controls::upscale(const QRect& rect) -{ - return QRect(upscale(rect.x(), Round::Floor), upscale(rect.y(), Round::Floor), - upscale(rect.width(), Round::Ceil), upscale(rect.height(), Round::Ceil)); -} - -inline QSize QtGraphics_Controls::downscale(const QSize& size, Round eRound) -{ - return QSize(downscale(size.width(), eRound), downscale(size.height(), eRound)); -} - -inline QSize QtGraphics_Controls::upscale(const QSize& size, Round eRound) -{ - return QSize(upscale(size.width(), eRound), upscale(size.height(), eRound)); -} - -inline QPoint QtGraphics_Controls::upscale(const QPoint& point, Round eRound) -{ - return QPoint(upscale(point.x(), eRound), upscale(point.y(), eRound)); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx deleted file mode 100644 index b375f77ce92a..000000000000 --- a/vcl/qt5/Qt5Graphics_GDI.cxx +++ /dev/null @@ -1,757 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Graphics.hxx> - -#include <Qt5Bitmap.hxx> -#include <Qt5Painter.hxx> - -#include <sal/log.hxx> - -#include <QtGui/QPainter> -#include <QtGui/QScreen> -#include <QtGui/QWindow> -#include <QtWidgets/QWidget> - -#include <numeric> -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <basegfx/polygon/b2dpolypolygontools.hxx> - -QtGraphicsBackend::QtGraphicsBackend(QtFrame* pFrame, QImage* pQImage) - : m_pFrame(pFrame) - , m_pQImage(pQImage) - , m_aLineColor(0x00, 0x00, 0x00) - , m_aFillColor(0xFF, 0xFF, 0XFF) - , m_eCompositionMode(QPainter::CompositionMode_SourceOver) -{ - ResetClipRegion(); -} - -QtGraphicsBackend::~QtGraphicsBackend() {} - -const basegfx::B2DPoint aHalfPointOfs(0.5, 0.5); - -static void AddPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolygon& rPolygon, - bool bClosePath, bool bPixelSnap, bool bLineDraw) -{ - const int nPointCount = rPolygon.count(); - // short circuit if there is nothing to do - if (nPointCount == 0) - return; - - const bool bHasCurves = rPolygon.areControlPointsUsed(); - for (int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++) - { - int nClosedIdx = nPointIdx; - if (nPointIdx >= nPointCount) - { - // prepare to close last curve segment if needed - if (bClosePath && (nPointIdx == nPointCount)) - nClosedIdx = 0; - else - break; - } - - basegfx::B2DPoint aPoint = rPolygon.getB2DPoint(nClosedIdx); - - if (bPixelSnap) - { - // snap device coordinates to full pixels - aPoint.setX(basegfx::fround(aPoint.getX())); - aPoint.setY(basegfx::fround(aPoint.getY())); - } - - if (bLineDraw) - aPoint += aHalfPointOfs; - if (!nPointIdx) - { - // first point => just move there - rPath.moveTo(aPoint.getX(), aPoint.getY()); - continue; - } - - bool bPendingCurve = false; - if (bHasCurves) - { - bPendingCurve = rPolygon.isNextControlPointUsed(nPrevIdx); - bPendingCurve |= rPolygon.isPrevControlPointUsed(nClosedIdx); - } - - if (!bPendingCurve) // line segment - rPath.lineTo(aPoint.getX(), aPoint.getY()); - else // cubic bezier segment - { - basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint(nPrevIdx); - basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint(nClosedIdx); - if (bLineDraw) - { - aCP1 += aHalfPointOfs; - aCP2 += aHalfPointOfs; - } - rPath.cubicTo(aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(), aPoint.getX(), - aPoint.getY()); - } - } - - if (bClosePath) - rPath.closeSubpath(); -} - -static bool AddPolyPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolyPolygon& rPolyPoly, - bool bPixelSnap, bool bLineDraw) -{ - if (rPolyPoly.count() == 0) - return false; - for (auto const& rPolygon : rPolyPoly) - { - AddPolygonToPath(rPath, rPolygon, true, bPixelSnap, bLineDraw); - } - return true; -} - -bool QtGraphicsBackend::setClipRegion(const vcl::Region& rRegion) -{ - if (rRegion.IsRectangle()) - { - m_aClipRegion = toQRect(rRegion.GetBoundRect()); - if (!m_aClipPath.isEmpty()) - { - QPainterPath aPath; - m_aClipPath.swap(aPath); - } - } - else if (!rRegion.HasPolyPolygonOrB2DPolyPolygon()) - { - QRegion aQRegion; - RectangleVector aRectangles; - rRegion.GetRegionRectangles(aRectangles); - for (const auto& rRect : aRectangles) - aQRegion += toQRect(rRect); - m_aClipRegion = aQRegion; - if (!m_aClipPath.isEmpty()) - { - QPainterPath aPath; - m_aClipPath.swap(aPath); - } - } - else - { - QPainterPath aPath; - const basegfx::B2DPolyPolygon aPolyClip(rRegion.GetAsB2DPolyPolygon()); - AddPolyPolygonToPath(aPath, aPolyClip, !getAntiAlias(), false); - m_aClipPath.swap(aPath); - if (!m_aClipRegion.isEmpty()) - { - QRegion aRegion; - m_aClipRegion.swap(aRegion); - } - } - return true; -} - -void QtGraphicsBackend::ResetClipRegion() -{ - if (m_pQImage) - m_aClipRegion = QRegion(m_pQImage->rect()); - else - m_aClipRegion = QRegion(); - if (!m_aClipPath.isEmpty()) - { - QPainterPath aPath; - m_aClipPath.swap(aPath); - } -} - -void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY) -{ - QtPainter aPainter(*this); - aPainter.drawPoint(nX, nY); - aPainter.update(nX, nY, 1, 1); -} - -void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY, Color nColor) -{ - QtPainter aPainter(*this); - aPainter.setPen(toQColor(nColor)); - aPainter.setPen(Qt::SolidLine); - aPainter.drawPoint(nX, nY); - aPainter.update(nX, nY, 1, 1); -} - -void QtGraphicsBackend::drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2) -{ - QtPainter aPainter(*this); - aPainter.drawLine(nX1, nY1, nX2, nY2); - - tools::Long tmp; - if (nX1 > nX2) - { - tmp = nX1; - nX1 = nX2; - nX2 = tmp; - } - if (nY1 > nY2) - { - tmp = nY1; - nY1 = nY2; - nY2 = tmp; - } - aPainter.update(nX1, nY1, nX2 - nX1 + 1, nY2 - nY1 + 1); -} - -void QtGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) -{ - if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) - return; - - QtPainter aPainter(*this, true); - if (SALCOLOR_NONE != m_aFillColor) - aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush()); - if (SALCOLOR_NONE != m_aLineColor) - aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1); - aPainter.update(nX, nY, nWidth, nHeight); -} - -void QtGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) -{ - if (0 == nPoints) - return; - - QtPainter aPainter(*this); - QPoint* pPoints = new QPoint[nPoints]; - QPoint aTopLeft(pPtAry->getX(), pPtAry->getY()); - QPoint aBottomRight = aTopLeft; - for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry) - { - pPoints[i] = QPoint(pPtAry->getX(), pPtAry->getY()); - if (pPtAry->getX() < aTopLeft.x()) - aTopLeft.setX(pPtAry->getX()); - if (pPtAry->getY() < aTopLeft.y()) - aTopLeft.setY(pPtAry->getY()); - if (pPtAry->getX() > aBottomRight.x()) - aBottomRight.setX(pPtAry->getX()); - if (pPtAry->getY() > aBottomRight.y()) - aBottomRight.setY(pPtAry->getY()); - } - aPainter.drawPolyline(pPoints, nPoints); - delete[] pPoints; - aPainter.update(QRect(aTopLeft, aBottomRight)); -} - -void QtGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) -{ - QtPainter aPainter(*this, true); - QPolygon aPolygon(nPoints); - for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry) - aPolygon.setPoint(i, pPtAry->getX(), pPtAry->getY()); - aPainter.drawPolygon(aPolygon); - aPainter.update(aPolygon.boundingRect()); -} - -void QtGraphicsBackend::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoints, - const Point** ppPtAry) -{ - // ignore invisible polygons - if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) - return; - - QPainterPath aPath; - for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++) - { - const sal_uInt32 nPoints = pPoints[nPoly]; - if (nPoints > 1) - { - const Point* pPtAry = ppPtAry[nPoly]; - aPath.moveTo(pPtAry->getX(), pPtAry->getY()); - pPtAry++; - for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++) - aPath.lineTo(pPtAry->getX(), pPtAry->getY()); - aPath.closeSubpath(); - } - } - - QtPainter aPainter(*this, true); - aPainter.drawPath(aPath); - aPainter.update(aPath.boundingRect()); -} - -bool QtGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolyPolygon& rPolyPolygon, - double fTransparency) -{ - // ignore invisible polygons - if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) - return true; - if ((fTransparency >= 1.0) || (fTransparency < 0)) - return true; - - // Fallback: Transform to DeviceCoordinates - basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); - aPolyPolygon.transform(rObjectToDevice); - - QPainterPath aPath; - // ignore empty polygons - if (!AddPolyPolygonToPath(aPath, aPolyPolygon, !getAntiAlias(), m_aLineColor != SALCOLOR_NONE)) - return true; - - QtPainter aPainter(*this, true, 255 * (1.0 - fTransparency)); - aPainter.drawPath(aPath); - aPainter.update(aPath.boundingRect()); - return true; -} - -bool QtGraphicsBackend::drawPolyLineBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/, - const PolyFlags* /*pFlgAry*/) -{ - return false; -} - -bool QtGraphicsBackend::drawPolygonBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/, - const PolyFlags* /*pFlgAry*/) -{ - return false; -} - -bool QtGraphicsBackend::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* /*pPoints*/, - const Point* const* /*pPtAry*/, - const PolyFlags* const* /*pFlgAry*/) -{ - return false; -} - -bool QtGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, - const basegfx::B2DPolygon& rPolyLine, double fTransparency, - double fLineWidth, - const std::vector<double>* pStroke, // MM01 - basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, - double fMiterMinimumAngle, bool bPixelSnapHairline) -{ - if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) - { - return true; - } - - // MM01 check done for simple reasons - if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0) - { - return true; - } - - // MM01 need to do line dashing as fallback stuff here now - const double fDotDashLength( - nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); - const bool bStrokeUsed(0.0 != fDotDashLength); - assert(!bStrokeUsed || (bStrokeUsed && pStroke)); - basegfx::B2DPolyPolygon aPolyPolygonLine; - - if (bStrokeUsed) - { - // apply LineStyle - basegfx::utils::applyLineDashing(rPolyLine, // source - *pStroke, // pattern - &aPolyPolygonLine, // target for lines - nullptr, // target for gaps - fDotDashLength); // full length if available - } - else - { - // no line dashing, just copy - aPolyPolygonLine.append(rPolyLine); - } - - // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline - aPolyPolygonLine.transform(rObjectToDevice); - if (bPixelSnapHairline) - { - aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); - } - - // tdf#124848 get correct LineWidth in discrete coordinates, - if (fLineWidth == 0) // hairline - fLineWidth = 1.0; - else // Adjust line width for object-to-device scale. - fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength(); - - // setup poly-polygon path - QPainterPath aPath; - - // MM01 todo - I assume that this is OKAY to be done in one run for Qt, - // but this NEEDS to be checked/verified - for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) - { - const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); - AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAlias(), true); - } - - QtPainter aPainter(*this, false, 255 * (1.0 - fTransparency)); - - // setup line attributes - QPen aPen = aPainter.pen(); - aPen.setWidth(fLineWidth); - - switch (eLineJoin) - { - case basegfx::B2DLineJoin::Bevel: - aPen.setJoinStyle(Qt::BevelJoin); - break; - case basegfx::B2DLineJoin::Round: - aPen.setJoinStyle(Qt::RoundJoin); - break; - case basegfx::B2DLineJoin::NONE: - case basegfx::B2DLineJoin::Miter: - aPen.setMiterLimit(1.0 / sin(fMiterMinimumAngle / 2.0)); - aPen.setJoinStyle(Qt::MiterJoin); - break; - } - - switch (eLineCap) - { - default: // css::drawing::LineCap_BUTT: - aPen.setCapStyle(Qt::FlatCap); - break; - case css::drawing::LineCap_ROUND: - aPen.setCapStyle(Qt::RoundCap); - break; - case css::drawing::LineCap_SQUARE: - aPen.setCapStyle(Qt::SquareCap); - break; - } - - aPainter.setPen(aPen); - aPainter.drawPath(aPath); - aPainter.update(aPath.boundingRect()); - return true; -} - -bool QtGraphicsBackend::drawGradient(const tools::PolyPolygon& /*rPolyPolygon*/, - const Gradient& /*rGradient*/) -{ - return false; -} - -bool QtGraphicsBackend::implDrawGradient(basegfx::B2DPolyPolygon const& /*rPolyPolygon*/, - SalGradient const& /*rGradient*/) -{ - return false; -} - -void QtGraphicsBackend::drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage) -{ - QtPainter aPainter(*this); - QRect aSrcRect(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); - QRect aDestRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); - aPainter.drawImage(aDestRect, rImage, aSrcRect); - aPainter.update(aDestRect); -} - -void QtGraphicsBackend::copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, - tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight, - bool /*bWindowInvalidate*/) -{ - if (nDestX == nSrcX && nDestY == nSrcY) - return; - - SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight); - - QImage* pImage = m_pQImage; - QImage aImage = pImage->copy(aTR.mnSrcX, aTR.mnSrcY, aTR.mnSrcWidth, aTR.mnSrcHeight); - pImage = &aImage; - aTR.mnSrcX = 0; - aTR.mnSrcY = 0; - - drawScaledImage(aTR, *pImage); -} - -void QtGraphicsBackend::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) -{ - if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 - || rPosAry.mnDestHeight <= 0) - return; - - QImage aImage, *pImage; - SalTwoRect aPosAry = rPosAry; - - if (!pSrcGraphics) - { - pImage = m_pQImage; - aImage - = pImage->copy(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); - pImage = &aImage; - aPosAry.mnSrcX = 0; - aPosAry.mnSrcY = 0; - } - else - pImage = static_cast<QtGraphics*>(pSrcGraphics)->getQImage(); - - drawScaledImage(aPosAry, *pImage); -} - -void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) -{ - if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 - || rPosAry.mnDestHeight <= 0) - return; - - const QImage* pImage = static_cast<const QtBitmap*>(&rSalBitmap)->GetQImage(); - - assert(pImage); - - drawScaledImage(rPosAry, *pImage); -} - -void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/, - const SalBitmap& /*rTransparentBitmap*/) -{ - if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 - || rPosAry.mnDestHeight <= 0) - return; - - assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth); - assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight); -} - -void QtGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/, - Color /*nMaskColor*/) -{ - if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 - || rPosAry.mnDestHeight <= 0) - return; - - assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth); - assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight); -} - -std::shared_ptr<SalBitmap> QtGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY, - tools::Long nWidth, tools::Long nHeight) -{ - return std::make_shared<QtBitmap>(m_pQImage->copy(nX, nY, nWidth, nHeight)); -} - -Color QtGraphicsBackend::getPixel(tools::Long nX, tools::Long nY) -{ - return Color(ColorTransparency, m_pQImage->pixel(nX, nY)); -} - -void QtGraphicsBackend::invert(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight, SalInvert nFlags) -{ - QtPainter aPainter(*this); - if (SalInvert::N50 & nFlags) - { - aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); - QBrush aBrush(Qt::white, Qt::Dense4Pattern); - aPainter.fillRect(nX, nY, nWidth, nHeight, aBrush); - } - else - { - if (SalInvert::TrackFrame & nFlags) - { - aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); - QPen aPen(Qt::white); - aPen.setStyle(Qt::DotLine); - aPainter.setPen(aPen); - aPainter.drawRect(nX, nY, nWidth, nHeight); - } - else - { - aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); - aPainter.fillRect(nX, nY, nWidth, nHeight, Qt::white); - } - } - aPainter.update(nX, nY, nWidth, nHeight); -} - -void QtGraphicsBackend::invert(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/, - SalInvert /*nFlags*/) -{ -} - -bool QtGraphicsBackend::drawEPS(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/, - tools::Long /*nHeight*/, void* /*pPtr*/, sal_uInt32 /*nSize*/) -{ - return false; -} - -bool QtGraphicsBackend::blendBitmap(const SalTwoRect&, const SalBitmap& /*rBitmap*/) -{ - return false; -} - -bool QtGraphicsBackend::blendAlphaBitmap(const SalTwoRect&, const SalBitmap& /*rSrcBitmap*/, - const SalBitmap& /*rMaskBitmap*/, - const SalBitmap& /*rAlphaBitmap*/) -{ - return false; -} - -static bool getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap, - QImage& rAlphaImage) -{ - if (rAlphaBitmap.GetBitCount() != 8 && rAlphaBitmap.GetBitCount() != 1) - { - SAL_WARN("vcl.gdi", "unsupported alpha depth case: " << rAlphaBitmap.GetBitCount()); - return false; - } - - const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage(); - const QImage* pAlpha = static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage(); - rAlphaImage = pBitmap->convertToFormat(Qt_DefaultFormat32); - - if (rAlphaBitmap.GetBitCount() == 8) - { - for (int y = 0; y < rAlphaImage.height(); ++y) - { - uchar* image_line = rAlphaImage.scanLine(y); - const uchar* alpha_line = pAlpha->scanLine(y); - for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4) - image_line[3] = 255 - alpha_line[x]; - } - } - else - { - for (int y = 0; y < rAlphaImage.height(); ++y) - { - uchar* image_line = rAlphaImage.scanLine(y); - const uchar* alpha_line = pAlpha->scanLine(y); - for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4) - { - if (x && !(x % 8)) - ++alpha_line; - if (0 != (*alpha_line & (1 << (7 - x % 8)))) - image_line[3] = 0; - } - } - } - - return true; -} - -bool QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap, - const SalBitmap& rAlphaBitmap) -{ - QImage aImage; - if (!getAlphaImage(rSourceBitmap, rAlphaBitmap, aImage)) - return false; - drawScaledImage(rPosAry, aImage); - return true; -} - -bool QtGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull, - const basegfx::B2DPoint& rX, - const basegfx::B2DPoint& rY, - const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) -{ - if (fAlpha != 1.0) - return false; - QImage aImage; - if (pAlphaBitmap && !getAlphaImage(rSourceBitmap, *pAlphaBitmap, aImage)) - return false; - else - { - const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage(); - aImage = pBitmap->convertToFormat(Qt_DefaultFormat32); - } - - QtPainter aPainter(*this); - const basegfx::B2DVector aXRel = rX - rNull; - const basegfx::B2DVector aYRel = rY - rNull; - aPainter.setTransform(QTransform(aXRel.getX() / aImage.width(), aXRel.getY() / aImage.width(), - aYRel.getX() / aImage.height(), aYRel.getY() / aImage.height(), - rNull.getX(), rNull.getY())); - aPainter.drawImage(QPoint(0, 0), aImage); - aPainter.update(aImage.rect()); - return true; -} - -bool QtGraphicsBackend::hasFastDrawTransformedBitmap() const { return false; } - -bool QtGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight, sal_uInt8 nTransparency) -{ - if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) - return true; - assert(nTransparency <= 100); - if (nTransparency > 100) - nTransparency = 100; - QtPainter aPainter(*this, true, (100 - nTransparency) * (255.0 / 100)); - if (SALCOLOR_NONE != m_aFillColor) - aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush()); - if (SALCOLOR_NONE != m_aLineColor) - aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1); - aPainter.update(nX, nY, nWidth, nHeight); - return true; -} - -sal_uInt16 QtGraphicsBackend::GetBitCount() const { return getFormatBits(m_pQImage->format()); } - -tools::Long QtGraphicsBackend::GetGraphicsWidth() const { return m_pQImage->width(); } - -void QtGraphicsBackend::SetLineColor() { m_aLineColor = SALCOLOR_NONE; } - -void QtGraphicsBackend::SetLineColor(Color nColor) { m_aLineColor = nColor; } - -void QtGraphicsBackend::SetFillColor() { m_aFillColor = SALCOLOR_NONE; } - -void QtGraphicsBackend::SetFillColor(Color nColor) { m_aFillColor = nColor; } - -void QtGraphicsBackend::SetXORMode(bool bSet, bool) -{ - if (bSet) - m_eCompositionMode = QPainter::CompositionMode_Xor; - else - m_eCompositionMode = QPainter::CompositionMode_SourceOver; -} - -void QtGraphicsBackend::SetROPLineColor(SalROPColor /*nROPColor*/) {} - -void QtGraphicsBackend::SetROPFillColor(SalROPColor /*nROPColor*/) {} - -bool QtGraphicsBackend::supportsOperation(OutDevSupportType eType) const -{ - switch (eType) - { - case OutDevSupportType::B2DDraw: - case OutDevSupportType::TransparentRect: - return true; - default: - return false; - } -} - -void QtGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) -{ - char* pForceDpi; - if ((pForceDpi = getenv("SAL_FORCEDPI"))) - { - OString sForceDPI(pForceDpi); - rDPIX = rDPIY = sForceDPI.toInt32(); - return; - } - - if (!m_pFrame || !m_pFrame->GetQWidget()->window()->windowHandle()) - return; - - QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen(); - rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5; - rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics_Text.cxx b/vcl/qt5/Qt5Graphics_Text.cxx deleted file mode 100644 index 411becfe914a..000000000000 --- a/vcl/qt5/Qt5Graphics_Text.cxx +++ /dev/null @@ -1,354 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * 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 <Qt5Graphics.hxx> -#include <Qt5FontFace.hxx> -#include <Qt5Font.hxx> -#include <Qt5Painter.hxx> - -#include <fontsubset.hxx> -#include <vcl/fontcharmap.hxx> -#include <unx/geninst.h> -#include <unx/fontmanager.hxx> -#include <unx/glyphcache.hxx> -#include <unx/genpspgraphics.h> - -#include <sallayout.hxx> -#include <PhysicalFontCollection.hxx> - -#include <QtGui/QGlyphRun> -#include <QtGui/QFontDatabase> -#include <QtGui/QRawFont> -#include <QtCore/QStringList> - -void QtGraphics::SetTextColor(Color nColor) { m_aTextColor = nColor; } - -void QtGraphics::SetFont(LogicalFontInstance* pReqFont, int nFallbackLevel) -{ - // release the text styles - for (int i = nFallbackLevel; i < MAX_FALLBACK; ++i) - { - if (!m_pTextStyle[i]) - break; - m_pTextStyle[i].clear(); - } - - if (!pReqFont) - return; - - m_pTextStyle[nFallbackLevel] = static_cast<QtFont*>(pReqFont); -} - -void QtGraphics::GetFontMetric(ImplFontMetricDataRef& rFMD, int nFallbackLevel) -{ - QRawFont aRawFont(QRawFont::fromFont(*m_pTextStyle[nFallbackLevel])); - QtFontFace::fillAttributesFromQFont(*m_pTextStyle[nFallbackLevel], *rFMD); - - rFMD->ImplCalcLineSpacing(m_pTextStyle[nFallbackLevel].get()); - - rFMD->SetSlant(0); - rFMD->SetWidth(aRawFont.averageCharWidth()); - - rFMD->SetMinKashida(m_pTextStyle[nFallbackLevel]->GetKashidaWidth()); -} - -FontCharMapRef QtGraphics::GetFontCharMap() const -{ - if (!m_pTextStyle[0]) - return FontCharMapRef(new FontCharMap()); - return m_pTextStyle[0]->GetFontFace()->GetFontCharMap(); -} - -bool QtGraphics::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const -{ - if (!m_pTextStyle[0]) - return false; - return m_pTextStyle[0]->GetFontFace()->GetFontCapabilities(rFontCapabilities); -} - -void QtGraphics::GetDevFontList(PhysicalFontCollection* pPFC) -{ - static const bool bUseFontconfig = (nullptr == getenv("SAL_VCL_QT5_NO_FONTCONFIG")); - - if (pPFC->Count()) - return; - - QFontDatabase aFDB; - FreetypeManager& rFontManager = FreetypeManager::get(); - psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); - ::std::vector<psp::fontID> aList; - psp::FastPrintFontInfo aInfo; - - rMgr.getFontList(aList); - for (auto const& elem : aList) - { - if (!rMgr.getFontFastInfo(elem, aInfo)) - continue; - - // normalize face number to the FreetypeManager - int nFaceNum = rMgr.getFontFaceNumber(aInfo.m_nID); - int nVariantNum = rMgr.getFontFaceVariation(aInfo.m_nID); - - // inform FreetypeManager about this font provided by the PsPrint subsystem - FontAttributes aDFA = GenPspGraphics::Info2FontAttributes(aInfo); - aDFA.IncreaseQualityBy(4096); - const OString& rFileName = rMgr.getFontFileSysPath(aInfo.m_nID); - rFontManager.AddFontFile(rFileName, nFaceNum, nVariantNum, aInfo.m_nID, aDFA); - } - - if (bUseFontconfig) - SalGenericInstance::RegisterFontSubstitutors(pPFC); - - for (auto& family : aFDB.families()) - for (auto& style : aFDB.styles(family)) - pPFC->Add(QtFontFace::fromQFontDatabase(family, style)); -} - -void QtGraphics::ClearDevFontCache() {} - -bool QtGraphics::AddTempDevFont(PhysicalFontCollection*, const OUString& /*rFileURL*/, - const OUString& /*rFontName*/) -{ - return false; -} - -namespace -{ -class QtTrueTypeFont : public vcl::AbstractTrueTypeFont -{ - const QRawFont& m_aRawFont; - mutable QByteArray m_aFontTable[vcl::NUM_TAGS]; - -public: - QtTrueTypeFont(const QtFontFace& aFontFace, const QRawFont& aRawFont); - - bool hasTable(sal_uInt32 ord) const override; - const sal_uInt8* table(sal_uInt32 ord, sal_uInt32& size) const override; -}; - -QtTrueTypeFont::QtTrueTypeFont(const QtFontFace& aFontFace, const QRawFont& aRawFont) - : vcl::AbstractTrueTypeFont(nullptr, aFontFace.GetFontCharMap()) - , m_aRawFont(aRawFont) -{ - indexGlyphData(); -} - -const char* vclFontTableAsChar(sal_uInt32 ord) -{ - switch (ord) - { - case vcl::O_maxp: - return "maxp"; - case vcl::O_glyf: - return "glyf"; - case vcl::O_head: - return "head"; - case vcl::O_loca: - return "loca"; - case vcl::O_name: - return "name"; - case vcl::O_hhea: - return "hhea"; - case vcl::O_hmtx: - return "hmtx"; - case vcl::O_cmap: - return "cmap"; - case vcl::O_vhea: - return "vhea"; - case vcl::O_vmtx: - return "vmtx"; - case vcl::O_OS2: - return "OS/2"; - case vcl::O_post: - return "post"; - case vcl::O_cvt: - return "cvt "; - case vcl::O_prep: - return "prep"; - case vcl::O_fpgm: - return "fpgm"; - case vcl::O_gsub: - return "gsub"; - case vcl::O_CFF: - return "CFF "; - default: - return nullptr; - } -} - -bool QtTrueTypeFont::hasTable(sal_uInt32 ord) const -{ - const char* table_char = vclFontTableAsChar(ord); - if (!table_char) - return false; - if (m_aFontTable[ord].isEmpty()) - m_aFontTable[ord] = m_aRawFont.fontTable(table_char); - return !m_aFontTable[ord].isEmpty(); -} - -const sal_uInt8* QtTrueTypeFont::table(sal_uInt32 ord, sal_uInt32& size) const -{ - const char* table_char = vclFontTableAsChar(ord); - if (!table_char) - return nullptr; - if (m_aFontTable[ord].isEmpty()) - m_aFontTable[ord] = m_aRawFont.fontTable(table_char); - size = m_aFontTable[ord].size(); - return reinterpret_cast<const sal_uInt8*>(m_aFontTable[ord].data()); -} -} - -bool QtGraphics::CreateFontSubset(const OUString& rToFile, const PhysicalFontFace* pFontFace, - const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, - sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo) -{ - OUString aSysPath; - if (osl_File_E_None != osl_getSystemPathFromFileURL(rToFile.pData, &aSysPath.pData)) - return false; - - // get the raw-bytes from the font to be subset - const QtFontFace* pQtFontFace = static_cast<const QtFontFace*>(pFontFace); - const QFont aFont = pQtFontFace->CreateFont(); - const QRawFont aRawFont(QRawFont::fromFont(aFont)); - const OString aToFile(OUStringToOString(aSysPath, osl_getThreadTextEncoding())); - - // handle CFF-subsetting - QByteArray aCFFtable = aRawFont.fontTable("CFF "); - if (!aCFFtable.isEmpty()) - return SalGraphics::CreateCFFfontSubset( - reinterpret_cast<const sal_uInt8*>(aCFFtable.data()), aCFFtable.size(), aToFile, - pGlyphIds, pEncoding, pGlyphWidths, nGlyphCount, rInfo); - - // fill details about the subsetted font - rInfo.m_nFontType = FontType::SFNT_TTF; - rInfo.m_aPSName = toOUString(aRawFont.familyName()); - rInfo.m_nCapHeight = aRawFont.capHeight(); - rInfo.m_nAscent = aRawFont.ascent(); - rInfo.m_nDescent = aRawFont.descent(); - - QtTrueTypeFont aTTF(*pQtFontFace, aRawFont); - int nXmin, nYmin, nXmax, nYmax; - sal_uInt16 nMacStyleFlags; - if (GetTTGlobalFontHeadInfo(&aTTF, nXmin, nYmin, nXmax, nYmax, nMacStyleFlags)) - rInfo.m_aFontBBox = tools::Rectangle(Point(nXmin, nYmin), Point(nXmax, nYmax)); - - return SalGraphics::CreateTTFfontSubset(aTTF, aToFile, false /* use FontSelectPattern? */, - pGlyphIds, pEncoding, pGlyphWidths, nGlyphCount); -} - -const void* QtGraphics::GetEmbedFontData(const PhysicalFontFace*, tools::Long* /*pDataLen*/) -{ - return nullptr; -} - -void QtGraphics::FreeEmbedFontData(const void* /*pData*/, tools::Long /*nDataLen*/) {} - -void QtGraphics::GetGlyphWidths(const PhysicalFontFace* pFontFace, bool bVertical, - std::vector<sal_Int32>& rWidths, Ucs2UIntMap& rUnicodeEnc) -{ - const QtFontFace* pQtFontFace = static_cast<const QtFontFace*>(pFontFace); - const QRawFont aRawFont(QRawFont::fromFont(pQtFontFace->CreateFont())); - QtTrueTypeFont aTTF(*pQtFontFace, aRawFont); - SalGraphics::GetGlyphWidths(aTTF, *pFontFace, bVertical, rWidths, rUnicodeEnc); -} - -namespace -{ -class QtCommonSalLayout : public GenericSalLayout -{ -public: - QtCommonSalLayout(LogicalFontInstance& rLFI) - : GenericSalLayout(rLFI) - { - } - - void SetOrientation(Degree10 nOrientation) { mnOrientation = nOrientation; } -}; -} - -std::unique_ptr<GenericSalLayout> QtGraphics::GetTextLayout(int nFallbackLevel) -{ - assert(m_pTextStyle[nFallbackLevel]); - if (!m_pTextStyle[nFallbackLevel]) - return nullptr; - return std::make_unique<QtCommonSalLayout>(*m_pTextStyle[nFallbackLevel]); -} - -void QtGraphics::DrawTextLayout(const GenericSalLayout& rLayout) -{ - const QtFont* pFont = static_cast<const QtFont*>(&rLayout.GetFont()); - assert(pFont); - QRawFont aRawFont(QRawFont::fromFont(*pFont)); - - QVector<quint32> glyphIndexes; - QVector<QPointF> positions; - - // prevent glyph rotation inside the SalLayout - // probably better to add a parameter to GetNextGlyphs? - QtCommonSalLayout* pQtLayout - = static_cast<QtCommonSalLayout*>(const_cast<GenericSalLayout*>(&rLayout)); - Degree10 nOrientation = rLayout.GetOrientation(); - if (nOrientation) - pQtLayout->SetOrientation(0_deg10); - - Point aPos; - const GlyphItem* pGlyph; - int nStart = 0; - while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) - { - glyphIndexes.push_back(pGlyph->glyphId()); - positions.push_back(QPointF(aPos.X(), aPos.Y())); - } - - // seems to be common to try to layout an empty string... - if (positions.empty()) - return; - - if (nOrientation) - pQtLayout->SetOrientation(nOrientation); - - QGlyphRun aGlyphRun; - aGlyphRun.setPositions(positions); - aGlyphRun.setGlyphIndexes(glyphIndexes); - aGlyphRun.setRawFont(aRawFont); - - QtPainter aPainter(*m_pBackend); - QColor aColor = toQColor(m_aTextColor); - aPainter.setPen(aColor); - - if (nOrientation) - { - // make text position the center of the rotation - // then rotate and move back - QRect window = aPainter.window(); - window.moveTo(-positions[0].x(), -positions[0].y()); - aPainter.setWindow(window); - - QTransform p; - p.rotate(-static_cast<qreal>(nOrientation.get()) / 10.0); - p.translate(-positions[0].x(), -positions[0].y()); - aPainter.setTransform(p); - } - - aPainter.drawGlyphRun(QPointF(), aGlyphRun); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Instance.cxx b/vcl/qt5/Qt5Instance.cxx deleted file mode 100644 index d93b25f5bb89..000000000000 --- a/vcl/qt5/Qt5Instance.cxx +++ /dev/null @@ -1,702 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Instance.hxx> -#include <Qt5Instance.moc> - -#include <com/sun/star/lang/IllegalArgumentException.hpp> - -#include <Qt5Bitmap.hxx> -#include <Qt5Clipboard.hxx> -#include <Qt5Data.hxx> -#include <Qt5DragAndDrop.hxx> -#include <Qt5FilePicker.hxx> -#include <Qt5Frame.hxx> -#include <Qt5Menu.hxx> -#include <Qt5Object.hxx> -#include <Qt5OpenGLContext.hxx> -#include "Qt5SvpVirtualDevice.hxx" -#include <Qt5System.hxx> -#include <Qt5Timer.hxx> -#include <Qt5VirtualDevice.hxx> - -#include <headless/svpvd.hxx> - -#include <QtCore/QAbstractEventDispatcher> -#include <QtCore/QThread> -#include <QtWidgets/QApplication> -#include <QtWidgets/QWidget> - -#include <vclpluginapi.h> -#include <tools/debug.hxx> -#include <comphelper/flagguard.hxx> -#include <sal/log.hxx> -#include <osl/process.h> -#include <unx/gstsink.hxx> -#include <headless/svpbmp.hxx> - -#include <mutex> -#include <condition_variable> - -#ifdef EMSCRIPTEN -#include <QtCore/QtPlugin> -Q_IMPORT_PLUGIN(QWasmIntegrationPlugin) -#endif - -namespace -{ -/// TODO: not much Qt specific here? could be generalised, esp. for OSX... -/// this subclass allows for the transfer of a closure for running on the main -/// thread, to handle all the thread affine stuff in Qt; the SolarMutex is -/// "loaned" to the main thread for the execution of the closure. -/// @note it doesn't work to just use "emit" and signals/slots to move calls to -/// the main thread, because the other thread has the SolarMutex; the other -/// thread (typically) cannot release SolarMutex, because then the main thread -/// will handle all sorts of events and whatnot; this design ensures that the -/// main thread only runs the passed closure (unless the closure releases -/// SolarMutex itself, which should probably be avoided). -class QtYieldMutex : public SalYieldMutex -{ -public: - /// flag only accessed on main thread: - /// main thread has "borrowed" SolarMutex from another thread - bool m_bNoYieldLock = false; - /// members for communication from non-main thread to main thread - std::mutex m_RunInMainMutex; - std::condition_variable m_InMainCondition; - bool m_isWakeUpMain = false; - std::function<void()> m_Closure; ///< code for main thread to run - /// members for communication from main thread to non-main thread - std::condition_variable m_ResultCondition; - bool m_isResultReady = false; - - virtual bool IsCurrentThread() const override; - virtual void doAcquire(sal_uInt32 nLockCount) override; - virtual sal_uInt32 doRelease(bool const bUnlockAll) override; -}; -} - -bool QtYieldMutex::IsCurrentThread() const -{ - auto const* pSalInst(static_cast<QtInstance const*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (pSalInst->IsMainThread() && m_bNoYieldLock) - { - return true; // main thread has borrowed SolarMutex - } - return SalYieldMutex::IsCurrentThread(); -} - -void QtYieldMutex::doAcquire(sal_uInt32 nLockCount) -{ - auto const* pSalInst(static_cast<QtInstance const*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - SalYieldMutex::doAcquire(nLockCount); - return; - } - if (m_bNoYieldLock) - { - return; // special case for main thread: borrowed from other thread - } - do // main thread acquire... - { - std::function<void()> func; // copy of closure on thread stack - { - std::unique_lock<std::mutex> g(m_RunInMainMutex); - if (m_aMutex.tryToAcquire()) - { - // if there's a closure, the other thread holds m_aMutex - assert(!m_Closure); - m_isWakeUpMain = false; - --nLockCount; // have acquired once! - ++m_nCount; - break; - } - m_InMainCondition.wait(g, [this]() { return m_isWakeUpMain; }); - m_isWakeUpMain = false; - std::swap(func, m_Closure); - } - if (func) - { - assert(!m_bNoYieldLock); - m_bNoYieldLock = true; // execute closure with borrowed SolarMutex - func(); - m_bNoYieldLock = false; - std::scoped_lock<std::mutex> g(m_RunInMainMutex); - assert(!m_isResultReady); - m_isResultReady = true; - m_ResultCondition.notify_all(); // unblock other thread - } - } while (true); - SalYieldMutex::doAcquire(nLockCount); -} - -sal_uInt32 QtYieldMutex::doRelease(bool const bUnlockAll) -{ - auto const* pSalInst(static_cast<QtInstance const*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (pSalInst->IsMainThread() && m_bNoYieldLock) - { - return 1; // dummy value - } - - std::scoped_lock<std::mutex> g(m_RunInMainMutex); - // read m_nCount before doRelease (it's guarded by m_aMutex) - bool const isReleased(bUnlockAll || m_nCount == 1); - sal_uInt32 nCount = SalYieldMutex::doRelease(bUnlockAll); - if (isReleased && !pSalInst->IsMainThread()) - { - m_isWakeUpMain = true; - m_InMainCondition.notify_all(); // unblock main thread - } - return nCount; -} - -// this could be abstracted to be independent of Qt by passing in the -// event-trigger as another function parameter... -// it could also be a template of the return type, then it could return the -// result of func... but then how to handle the result in doAcquire? -void QtInstance::RunInMainThread(std::function<void()> func) -{ - DBG_TESTSOLARMUTEX(); - if (IsMainThread()) - { - func(); - return; - } - - QtYieldMutex* const pMutex(static_cast<QtYieldMutex*>(GetYieldMutex())); - { - std::scoped_lock<std::mutex> g(pMutex->m_RunInMainMutex); - assert(!pMutex->m_Closure); - pMutex->m_Closure = func; - // unblock main thread in case it is blocked on condition - pMutex->m_isWakeUpMain = true; - pMutex->m_InMainCondition.notify_all(); - } - - TriggerUserEventProcessing(); - { - std::unique_lock<std::mutex> g(pMutex->m_RunInMainMutex); - pMutex->m_ResultCondition.wait(g, [pMutex]() { return pMutex->m_isResultReady; }); - pMutex->m_isResultReady = false; - } -} - -OUString QtInstance::constructToolkitID(std::u16string_view sTKname) -{ - OUString sID(sTKname + OUString::Concat(u" (")); - if (m_bUseCairo) - sID += "cairo+"; - else - sID += "qfont+"; - sID += toOUString(QGuiApplication::platformName()) + OUString::Concat(u")"); - return sID; -} - -QtInstance::QtInstance(std::unique_ptr<QApplication>& pQApp, bool bUseCairo) - : SalGenericInstance(std::make_unique<QtYieldMutex>()) - , m_bUseCairo(bUseCairo) - , m_pTimer(nullptr) - , m_bSleeping(false) - , m_pQApplication(std::move(pQApp)) - , m_aUpdateStyleTimer("vcl::qt5 m_aUpdateStyleTimer") - , m_bUpdateFonts(false) -{ - ImplSVData* pSVData = ImplGetSVData(); - pSVData->maAppData.mxToolkitName = constructToolkitID(u"qt5"); - - // this one needs to be blocking, so that the handling in main thread - // is processed before the thread emitting the signal continues - connect(this, SIGNAL(ImplYieldSignal(bool, bool)), this, SLOT(ImplYield(bool, bool)), - Qt::BlockingQueuedConnection); - - // this one needs to be queued non-blocking - // in order to have this event arriving to correct event processing loop - connect(this, &QtInstance::deleteObjectLaterSignal, this, - [](QObject* pObject) { QtInstance::deleteObjectLater(pObject); }, Qt::QueuedConnection); - - m_aUpdateStyleTimer.SetTimeout(50); - m_aUpdateStyleTimer.SetInvokeHandler(LINK(this, QtInstance, updateStyleHdl)); - - QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); - connect(dispatcher, &QAbstractEventDispatcher::awake, this, [this]() { m_bSleeping = false; }); - connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, - [this]() { m_bSleeping = true; }); - - connect(QGuiApplication::inputMethod(), &QInputMethod::localeChanged, this, - &QtInstance::localeChanged); - -#ifndef EMSCRIPTEN - m_bSupportsOpenGL = true; -#endif -} - -QtInstance::~QtInstance() -{ - // force freeing the QApplication before freeing the arguments, - // as it uses references to the provided arguments! - m_pQApplication.reset(); -} - -void QtInstance::AfterAppInit() -{ - // set the default application icon via desktop file just on Wayland, - // as this otherwise overrides the individual desktop icons on X11. - if (QGuiApplication::platformName() == "wayland") - QGuiApplication::setDesktopFileName(QStringLiteral("libreoffice-startcenter.desktop")); - QGuiApplication::setLayoutDirection(AllSettings::GetLayoutRTL() ? Qt::RightToLeft - : Qt::LeftToRight); -} - -void QtInstance::localeChanged() -{ - SolarMutexGuard aGuard; - const vcl::Window* pFocusWindow = Application::GetFocusWindow(); - SalFrame* const pFocusFrame = pFocusWindow ? pFocusWindow->ImplGetFrame() : nullptr; - if (!pFocusFrame) - return; - - const LanguageTag aTag( - toOUString(QGuiApplication::inputMethod()->locale().name().replace("_", "-"))); - static_cast<QtFrame*>(pFocusFrame)->setInputLanguage(aTag.getLanguageType()); -} - -void QtInstance::deleteObjectLater(QObject* pObject) { pObject->deleteLater(); } - -SalFrame* QtInstance::CreateChildFrame(SystemParentData* /*pParent*/, SalFrameStyleFlags nStyle) -{ - SalFrame* pRet(nullptr); - RunInMainThread([&, this]() { pRet = new QtFrame(nullptr, nStyle, useCairo()); }); - assert(pRet); - return pRet; -} - -SalFrame* QtInstance::CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) -{ - assert(!pParent || dynamic_cast<QtFrame*>(pParent)); - - SalFrame* pRet(nullptr); - RunInMainThread( - [&, this]() { pRet = new QtFrame(static_cast<QtFrame*>(pParent), nStyle, useCairo()); }); - assert(pRet); - return pRet; -} - -void QtInstance::DestroyFrame(SalFrame* pFrame) -{ - if (pFrame) - { - assert(dynamic_cast<QtFrame*>(pFrame)); - Q_EMIT deleteObjectLaterSignal(static_cast<QtFrame*>(pFrame)); - } -} - -SalObject* QtInstance::CreateObject(SalFrame* pParent, SystemWindowData*, bool bShow) -{ - assert(!pParent || dynamic_cast<QtFrame*>(pParent)); - - SalObject* pRet(nullptr); - RunInMainThread([&]() { pRet = new QtObject(static_cast<QtFrame*>(pParent), bShow); }); - assert(pRet); - return pRet; -} - -void QtInstance::DestroyObject(SalObject* pObject) -{ - if (pObject) - { - assert(dynamic_cast<QtObject*>(pObject)); - Q_EMIT deleteObjectLaterSignal(static_cast<QtObject*>(pObject)); - } -} - -std::unique_ptr<SalVirtualDevice> -QtInstance::CreateVirtualDevice(SalGraphics& rGraphics, tools::Long& nDX, tools::Long& nDY, - DeviceFormat /*eFormat*/, const SystemGraphicsData* pGd) -{ - if (m_bUseCairo) - { - SvpSalGraphics* pSvpSalGraphics = dynamic_cast<QtSvpGraphics*>(&rGraphics); - assert(pSvpSalGraphics); - // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget - cairo_surface_t* pPreExistingTarget - = pGd ? static_cast<cairo_surface_t*>(pGd->pSurface) : nullptr; - std::unique_ptr<SalVirtualDevice> pVD( - new QtSvpVirtualDevice(pSvpSalGraphics->getSurface(), pPreExistingTarget)); - pVD->SetSize(nDX, nDY); - return pVD; - } - else - { - std::unique_ptr<SalVirtualDevice> pVD(new QtVirtualDevice(/*scale*/ 1)); - pVD->SetSize(nDX, nDY); - return pVD; - } -} - -std::unique_ptr<SalMenu> QtInstance::CreateMenu(bool bMenuBar, Menu* pVCLMenu) -{ - std::unique_ptr<SalMenu> pRet; - RunInMainThread([&pRet, bMenuBar, pVCLMenu]() { - QtMenu* pSalMenu = new QtMenu(bMenuBar); - pRet.reset(pSalMenu); - pSalMenu->SetMenu(pVCLMenu); - }); - assert(pRet); - return pRet; -} - -std::unique_ptr<SalMenuItem> QtInstance::CreateMenuItem(const SalItemParams& rItemData) -{ - return std::unique_ptr<SalMenuItem>(new QtMenuItem(&rItemData)); -} - -SalTimer* QtInstance::CreateSalTimer() -{ - m_pTimer = new QtTimer(); - return m_pTimer; -} - -SalSystem* QtInstance::CreateSalSystem() { return new QtSystem; } - -std::shared_ptr<SalBitmap> QtInstance::CreateSalBitmap() -{ - if (m_bUseCairo) - return std::make_shared<SvpSalBitmap>(); - else - return std::make_shared<QtBitmap>(); -} - -bool QtInstance::ImplYield(bool bWait, bool bHandleAllCurrentEvents) -{ - // Re-acquire the guard for user events when called via Q_EMIT ImplYieldSignal - SolarMutexGuard aGuard; - bool wasEvent = DispatchUserEvents(bHandleAllCurrentEvents); - if (!bHandleAllCurrentEvents && wasEvent) - return true; - - /** - * Quoting the Qt docs: [QAbstractEventDispatcher::processEvents] processes - * pending events that match flags until there are no more events to process. - */ - SolarMutexReleaser aReleaser; - QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); - if (bWait && !wasEvent) - wasEvent = dispatcher->processEvents(QEventLoop::WaitForMoreEvents); - else - wasEvent = dispatcher->processEvents(QEventLoop::AllEvents) || wasEvent; - return wasEvent; -} - -bool QtInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) -{ - bool bWasEvent = false; - if (qApp->thread() == QThread::currentThread()) - { - bWasEvent = ImplYield(bWait, bHandleAllCurrentEvents); - if (bWasEvent) - m_aWaitingYieldCond.set(); - } - else - { - { - SolarMutexReleaser aReleaser; - bWasEvent = Q_EMIT ImplYieldSignal(false, bHandleAllCurrentEvents); - } - if (!bWasEvent && bWait) - { - m_aWaitingYieldCond.reset(); - SolarMutexReleaser aReleaser; - m_aWaitingYieldCond.wait(); - bWasEvent = true; - } - } - return bWasEvent; -} - -bool QtInstance::AnyInput(VclInputFlags nType) -{ - bool bResult = false; - if (nType & VclInputFlags::TIMER) - bResult |= (m_pTimer && m_pTimer->remainingTime() == 0); - if (nType & VclInputFlags::OTHER) - bResult |= !m_bSleeping; - return bResult; -} - -OUString QtInstance::GetConnectionIdentifier() { return OUString(); } - -void QtInstance::AddToRecentDocumentList(const OUString&, const OUString&, const OUString&) {} - -#ifndef EMSCRIPTEN -OpenGLContext* QtInstance::CreateOpenGLContext() { return new QtOpenGLContext; } -#endif - -bool QtInstance::IsMainThread() const -{ - return !qApp || (qApp->thread() == QThread::currentThread()); -} - -void QtInstance::TriggerUserEventProcessing() -{ - QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); - dispatcher->wakeUp(); -} - -void QtInstance::ProcessEvent(SalUserEvent aEvent) -{ - aEvent.m_pFrame->CallCallback(aEvent.m_nEvent, aEvent.m_pData); -} - -rtl::Reference<QtFilePicker> -QtInstance::createPicker(css::uno::Reference<css::uno::XComponentContext> const& context, - QFileDialog::FileMode eMode) -{ - if (!IsMainThread()) - { - SolarMutexGuard g; - rtl::Reference<QtFilePicker> pPicker; - RunInMainThread([&, this]() { pPicker = createPicker(context, eMode); }); - assert(pPicker); - return pPicker; - } - - return new QtFilePicker(context, eMode); -} - -css::uno::Reference<css::ui::dialogs::XFilePicker2> -QtInstance::createFilePicker(const css::uno::Reference<css::uno::XComponentContext>& context) -{ - return css::uno::Reference<css::ui::dialogs::XFilePicker2>( - createPicker(context, QFileDialog::ExistingFile)); -} - -css::uno::Reference<css::ui::dialogs::XFolderPicker2> -QtInstance::createFolderPicker(const css::uno::Reference<css::uno::XComponentContext>& context) -{ - return css::uno::Reference<css::ui::dialogs::XFolderPicker2>( - createPicker(context, QFileDialog::Directory)); -} - -css::uno::Reference<css::uno::XInterface> -QtInstance::CreateClipboard(const css::uno::Sequence<css::uno::Any>& arguments) -{ - OUString sel; - if (arguments.getLength() == 0) - { - sel = "CLIPBOARD"; - } - else if (arguments.getLength() != 1 || !(arguments[0] >>= sel)) - { - throw css::lang::IllegalArgumentException("bad QtInstance::CreateClipboard arguments", - css::uno::Reference<css::uno::XInterface>(), -1); - } - - // This could also use RunInMain, but SolarMutexGuard is enough - // since at this point we're not accessing the clipboard, just get the - // accessor to the clipboard. - SolarMutexGuard aGuard; - - auto it = m_aClipboards.find(sel); - if (it != m_aClipboards.end()) - return it->second; - - css::uno::Reference<css::uno::XInterface> xClipboard = QtClipboard::create(sel); - if (xClipboard.is()) - m_aClipboards[sel] = xClipboard; - - return xClipboard; -} - -css::uno::Reference<css::uno::XInterface> QtInstance::CreateDragSource() -{ - return css::uno::Reference<css::uno::XInterface>( - static_cast<cppu::OWeakObject*>(new QtDragSource())); -} - -css::uno::Reference<css::uno::XInterface> QtInstance::CreateDropTarget() -{ - return css::uno::Reference<css::uno::XInterface>( - static_cast<cppu::OWeakObject*>(new QtDropTarget())); -} - -IMPL_LINK_NOARG(QtInstance, updateStyleHdl, Timer*, void) -{ - SolarMutexGuard aGuard; - SalFrame* pFrame = anyFrame(); - if (pFrame) - { - pFrame->CallCallback(SalEvent::SettingsChanged, nullptr); - if (m_bUpdateFonts) - { - pFrame->CallCallback(SalEvent::FontChanged, nullptr); - m_bUpdateFonts = false; - } - } -} - -void QtInstance::UpdateStyle(bool bFontsChanged) -{ - if (bFontsChanged) - m_bUpdateFonts = true; - if (!m_aUpdateStyleTimer.IsActive()) - m_aUpdateStyleTimer.Start(); -} - -void* QtInstance::CreateGStreamerSink(const SystemChildWindow* pWindow) -{ -#if ENABLE_GSTREAMER_1_0 && QT5_HAVE_GOBJECT - auto pSymbol = gstElementFactoryNameSymbol(); - if (!pSymbol) - return nullptr; - - const SystemEnvData* pEnvData = pWindow->GetSystemData(); - if (!pEnvData) - return nullptr; - - if (pEnvData->platform != SystemEnvData::Platform::Wayland) - return nullptr; - - GstElement* pVideosink = pSymbol("qwidget5videosink", "qwidget5videosink"); - if (pVideosink) - { - QWidget* pQWidget = static_cast<QWidget*>(pEnvData->pWidget); - g_object_set(G_OBJECT(pVideosink), "widget", pQWidget, nullptr); - } - else - { - SAL_WARN("vcl.qt5", "Couldn't initialize qwidget5videosink." - " Video playback might not work as expected." - " Please install Qt5 packages for QtGStreamer."); - // with no videosink explicitly set, GStreamer will open its own (misplaced) window(s) to display video - } - - return pVideosink; -#else - Q_UNUSED(pWindow); - return nullptr; -#endif -} - -void QtInstance::AllocFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, - std::unique_ptr<int>& rFakeArgc, - std::vector<FreeableCStr>& rFakeArgvFreeable) -{ - OString aVersion(qVersion()); - SAL_INFO("vcl.qt5", "qt version string is " << aVersion); - - const sal_uInt32 nParams = osl_getCommandArgCount(); - sal_uInt32 nDisplayValueIdx = 0; - OUString aParam, aBin; - - for (sal_uInt32 nIdx = 0; nIdx < nParams; ++nIdx) - { - osl_getCommandArg(nIdx, &aParam.pData); - if (aParam != "-display") - continue; - ++nIdx; - nDisplayValueIdx = nIdx; - } - - osl_getExecutableFile(&aParam.pData); - osl_getSystemPathFromFileURL(aParam.pData, &aBin.pData); - OString aExec = OUStringToOString(aBin, osl_getThreadTextEncoding()); - - std::vector<FreeableCStr> aFakeArgvFreeable; - aFakeArgvFreeable.reserve(4); - aFakeArgvFreeable.emplace_back(strdup(aExec.getStr())); - aFakeArgvFreeable.emplace_back(strdup("--nocrashhandler")); - if (nDisplayValueIdx) - { - aFakeArgvFreeable.emplace_back(strdup("-display")); - osl_getCommandArg(nDisplayValueIdx, &aParam.pData); - OString aDisplay = OUStringToOString(aParam, osl_getThreadTextEncoding()); - aFakeArgvFreeable.emplace_back(strdup(aDisplay.getStr())); - } - rFakeArgvFreeable.swap(aFakeArgvFreeable); - - const int nFakeArgc = rFakeArgvFreeable.size(); - rFakeArgv.reset(new char*[nFakeArgc]); - for (int i = 0; i < nFakeArgc; i++) - rFakeArgv[i] = rFakeArgvFreeable[i].get(); - - rFakeArgc.reset(new int); - *rFakeArgc = nFakeArgc; -} - -void QtInstance::MoveFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, - std::unique_ptr<int>& rFakeArgc, - std::vector<FreeableCStr>& rFakeArgvFreeable) -{ - m_pFakeArgv = std::move(rFakeArgv); - m_pFakeArgc = std::move(rFakeArgc); - m_pFakeArgvFreeable.swap(rFakeArgvFreeable); -} - -std::unique_ptr<QApplication> QtInstance::CreateQApplication(int& nArgc, char** pArgv) -{ - QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - // for scaled icons in the native menus - QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - - FreeableCStr session_manager; - if (getenv("SESSION_MANAGER") != nullptr) - { - session_manager.reset(strdup(getenv("SESSION_MANAGER"))); - unsetenv("SESSION_MANAGER"); - } - - std::unique_ptr<QApplication> pQApp = std::make_unique<QApplication>(nArgc, pArgv); - - if (session_manager != nullptr) - { - // coverity[tainted_string] - trusted source for setenv - setenv("SESSION_MANAGER", session_manager.get(), 1); - } - - QApplication::setQuitOnLastWindowClosed(false); - return pQApp; -} - -extern "C" { -VCLPLUG_QT5_PUBLIC SalInstance* create_SalInstance() -{ - static const bool bUseCairo = (nullptr != getenv("SAL_VCL_QT5_USE_CAIRO")); - - std::unique_ptr<char* []> pFakeArgv; - std::unique_ptr<int> pFakeArgc; - std::vector<FreeableCStr> aFakeArgvFreeable; - QtInstance::AllocFakeCmdlineArgs(pFakeArgv, pFakeArgc, aFakeArgvFreeable); - - std::unique_ptr<QApplication> pQApp - = QtInstance::CreateQApplication(*pFakeArgc, pFakeArgv.get()); - - QtInstance* pInstance = new QtInstance(pQApp, bUseCairo); - pInstance->MoveFakeCmdlineArgs(pFakeArgv, pFakeArgc, aFakeArgvFreeable); - - new QtData(pInstance); - - return pInstance; -} -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Instance_Print.cxx b/vcl/qt5/Qt5Instance_Print.cxx deleted file mode 100644 index 2f9a096f7eb9..000000000000 --- a/vcl/qt5/Qt5Instance_Print.cxx +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * 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 <Qt5Instance.hxx> -#include <Qt5Printer.hxx> - -#include <vcl/svapp.hxx> -#include <vcl/timer.hxx> -#include <vcl/QueueInfo.hxx> -#include <printerinfomanager.hxx> - -#include <jobset.h> -#include <print.h> -#include <salptype.hxx> -#include <saldatabasic.hxx> - -#include <unx/genpspgraphics.h> - -using namespace psp; - -/* - * static helpers - */ - -static OUString getPdfDir(const PrinterInfo& rInfo) -{ - OUString aDir; - sal_Int32 nIndex = 0; - while (nIndex != -1) - { - OUString aToken(rInfo.m_aFeatures.getToken(0, ',', nIndex)); - if (aToken.startsWith("pdf=")) - { - sal_Int32 nPos = 0; - aDir = aToken.getToken(1, '=', nPos); - if (aDir.isEmpty()) - if (auto const env = getenv("HOME")) - { - aDir = OStringToOUString(std::string_view(env), osl_getThreadTextEncoding()); - } - break; - } - } - return aDir; -} - -SalInfoPrinter* QtInstance::CreateInfoPrinter(SalPrinterQueueInfo* pQueueInfo, - ImplJobSetup* pJobSetup) -{ - // create and initialize SalInfoPrinter - PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter; - configurePspInfoPrinter(pPrinter, pQueueInfo, pJobSetup); - - return pPrinter; -} - -void QtInstance::DestroyInfoPrinter(SalInfoPrinter* pPrinter) { delete pPrinter; } - -std::unique_ptr<SalPrinter> QtInstance::CreatePrinter(SalInfoPrinter* pInfoPrinter) -{ - // create and initialize SalPrinter - QtPrinter* pPrinter = new QtPrinter(pInfoPrinter); - pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData; - - return std::unique_ptr<SalPrinter>(pPrinter); -} - -void QtInstance::GetPrinterQueueInfo(ImplPrnQueueList* pList) -{ - PrinterInfoManager& rManager(PrinterInfoManager::get()); - static const char* pNoSyncDetection = getenv("SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION"); - if (!pNoSyncDetection || !*pNoSyncDetection) - { - // #i62663# synchronize possible asynchronouse printer detection now - rManager.checkPrintersChanged(true); - } - ::std::vector<OUString> aPrinters; - rManager.listPrinters(aPrinters); - - for (const auto& rPrinter : aPrinters) - { - const PrinterInfo& rInfo(rManager.getPrinterInfo(rPrinter)); - // create new entry - std::unique_ptr<SalPrinterQueueInfo> pInfo(new SalPrinterQueueInfo); - pInfo->maPrinterName = rPrinter; - pInfo->maDriver = rInfo.m_aDriverName; - pInfo->maLocation = rInfo.m_aLocation; - pInfo->maComment = rInfo.m_aComment; - - sal_Int32 nIndex = 0; - while (nIndex != -1) - { - OUString aToken(rInfo.m_aFeatures.getToken(0, ',', nIndex)); - if (aToken.startsWith("pdf=")) - { - pInfo->maLocation = getPdfDir(rInfo); - break; - } - } - - pList->Add(std::move(pInfo)); - } -} - -void QtInstance::GetPrinterQueueState(SalPrinterQueueInfo*) {} - -OUString QtInstance::GetDefaultPrinter() -{ - PrinterInfoManager& rManager(PrinterInfoManager::get()); - return rManager.getDefaultPrinter(); -} - -void QtInstance::PostPrintersChanged() {} - -std::unique_ptr<GenPspGraphics> QtInstance::CreatePrintGraphics() -{ - return std::make_unique<GenPspGraphics>(); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5MainWindow.cxx b/vcl/qt5/Qt5MainWindow.cxx deleted file mode 100644 index 3f8814cad73d..000000000000 --- a/vcl/qt5/Qt5MainWindow.cxx +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <Qt5MainWindow.hxx> -#include <Qt5MainWindow.moc> -#include <Qt5AccessibleWidget.hxx> - -#include <QtGui/QAccessible> -#include <QtGui/QCloseEvent> - -QtMainWindow::QtMainWindow(QtFrame& rFrame, Qt::WindowFlags f) - : QMainWindow(nullptr, f) - , m_rFrame(rFrame) -{ -#ifndef EMSCRIPTEN - QAccessible::installFactory(QtAccessibleWidget::customFactory); -#endif -} - -void QtMainWindow::closeEvent(QCloseEvent* pEvent) -{ - bool bRet = false; - bRet = m_rFrame.CallCallback(SalEvent::Close, nullptr); - - if (bRet) - pEvent->accept(); - // SalEvent::Close returning false may mean that user has vetoed - // closing the frame ("you have unsaved changes" dialog for example) - // We shouldn't process the event in such case - else - pEvent->ignore(); -} - -void QtMainWindow::moveEvent(QMoveEvent* pEvent) -{ - const qreal fRatio = m_rFrame.devicePixelRatioF(); - m_rFrame.maGeometry.nX = round(pEvent->pos().x() * fRatio); - m_rFrame.maGeometry.nY = round(pEvent->pos().y() * fRatio); - m_rFrame.CallCallback(SalEvent::Move, nullptr); -} diff --git a/vcl/qt5/Qt5Menu.cxx b/vcl/qt5/Qt5Menu.cxx deleted file mode 100644 index ace199df9f88..000000000000 --- a/vcl/qt5/Qt5Menu.cxx +++ /dev/null @@ -1,702 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <Qt5Menu.hxx> -#include <Qt5Menu.moc> - -#include <Qt5Frame.hxx> -#include <Qt5Instance.hxx> -#include <Qt5MainWindow.hxx> - -#include <QtWidgets/QMenuBar> -#include <QtWidgets/QPushButton> - -#include <o3tl/safeint.hxx> -#include <vcl/svapp.hxx> -#include <sal/log.hxx> - -#include <strings.hrc> -#include <bitmaps.hlst> - -#include <vcl/toolkit/floatwin.hxx> -#include <window.h> - -QtMenu::QtMenu(bool bMenuBar) - : mpVCLMenu(nullptr) - , mpParentSalMenu(nullptr) - , mpFrame(nullptr) - , mbMenuBar(bMenuBar) - , mpQMenuBar(nullptr) - , mpQMenu(nullptr) - , mpCloseButton(nullptr) -{ -} - -bool QtMenu::VisibleMenuBar() { return true; } - -void QtMenu::InsertMenuItem(QtMenuItem* pSalMenuItem, unsigned nPos) -{ - sal_uInt16 nId = pSalMenuItem->mnId; - OUString aText = mpVCLMenu->GetItemText(nId); - NativeItemText(aText); - vcl::KeyCode nAccelKey = mpVCLMenu->GetAccelKey(nId); - - pSalMenuItem->mpAction.reset(); - pSalMenuItem->mpMenu.reset(); - - if (mbMenuBar) - { - // top-level menu - if (mpQMenuBar) - { - QMenu* pQMenu = new QMenu(toQString(aText), nullptr); - pSalMenuItem->mpMenu.reset(pQMenu); - - if ((nPos != MENU_APPEND) - && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenuBar->actions().size()))) - { - mpQMenuBar->insertMenu(mpQMenuBar->actions()[nPos], pQMenu); - } - else - { - mpQMenuBar->addMenu(pQMenu); - } - - // correct parent menu for generated menu - if (pSalMenuItem->mpSubMenu) - { - pSalMenuItem->mpSubMenu->mpQMenu = pQMenu; - } - - connect(pQMenu, &QMenu::aboutToShow, this, - [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); }); - connect(pQMenu, &QMenu::aboutToHide, this, - [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); }); - } - } - else - { - if (!mpQMenu) - { - // no QMenu set, instantiate own one - mpOwnedQMenu.reset(new QMenu); - mpQMenu = mpOwnedQMenu.get(); - } - - if (pSalMenuItem->mpSubMenu) - { - // submenu - QMenu* pQMenu = new QMenu(toQString(aText), nullptr); - pSalMenuItem->mpMenu.reset(pQMenu); - - if ((nPos != MENU_APPEND) - && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) - { - mpQMenu->insertMenu(mpQMenu->actions()[nPos], pQMenu); - } - else - { - mpQMenu->addMenu(pQMenu); - } - - // correct parent menu for generated menu - pSalMenuItem->mpSubMenu->mpQMenu = pQMenu; - - ReinitializeActionGroup(nPos); - - // clear all action groups since menu is recreated - pSalMenuItem->mpSubMenu->ResetAllActionGroups(); - - connect(pQMenu, &QMenu::aboutToShow, this, - [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); }); - connect(pQMenu, &QMenu::aboutToHide, this, - [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); }); - } - else - { - if (pSalMenuItem->mnType == MenuItemType::SEPARATOR) - { - QAction* pAction = new QAction(nullptr); - pSalMenuItem->mpAction.reset(pAction); - pAction->setSeparator(true); - - if ((nPos != MENU_APPEND) - && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) - { - mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction); - } - else - { - mpQMenu->addAction(pAction); - } - - ReinitializeActionGroup(nPos); - } - else - { - // leaf menu - QAction* pAction = new QAction(toQString(aText), nullptr); - pSalMenuItem->mpAction.reset(pAction); - - if ((nPos != MENU_APPEND) - && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) - { - mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction); - } - else - { - mpQMenu->addAction(pAction); - } - - ReinitializeActionGroup(nPos); - - UpdateActionGroupItem(pSalMenuItem); - - pAction->setShortcut(toQString(nAccelKey.GetName())); - - connect(pAction, &QAction::triggered, this, - [pSalMenuItem] { slotMenuTriggered(pSalMenuItem); }); - } - } - } - - QAction* pAction = pSalMenuItem->getAction(); - if (pAction) - { - pAction->setEnabled(pSalMenuItem->mbEnabled); - pAction->setVisible(pSalMenuItem->mbVisible); - } -} - -void QtMenu::ReinitializeActionGroup(unsigned nPos) -{ - const unsigned nCount = GetItemCount(); - - if (nCount == 0) - { - return; - } - - if (nPos == MENU_APPEND) - { - nPos = nCount - 1; - } - else if (nPos >= nCount) - { - return; - } - - QtMenuItem* pPrevItem = (nPos > 0) ? GetItemAtPos(nPos - 1) : nullptr; - QtMenuItem* pCurrentItem = GetItemAtPos(nPos); - QtMenuItem* pNextItem = (nPos < nCount - 1) ? GetItemAtPos(nPos + 1) : nullptr; - - if (pCurrentItem->mnType == MenuItemType::SEPARATOR) - { - pCurrentItem->mpActionGroup.reset(); - - // if it's inserted into middle of existing group, split it into two groups: - // first goes original group, after separator goes new group - if (pPrevItem && pPrevItem->mpActionGroup && pNextItem && pNextItem->mpActionGroup - && (pPrevItem->mpActionGroup == pNextItem->mpActionGroup)) - { - std::shared_ptr<QActionGroup> pFirstActionGroup = pPrevItem->mpActionGroup; - auto pSecondActionGroup = std::make_shared<QActionGroup>(nullptr); - pSecondActionGroup->setExclusive(true); - - auto actions = pFirstActionGroup->actions(); - - for (unsigned idx = nPos + 1; idx < nCount; ++idx) - { - QtMenuItem* pModifiedItem = GetItemAtPos(idx); - - if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup)) - { - break; - } - - pModifiedItem->mpActionGroup = pSecondActionGroup; - auto action = pModifiedItem->getAction(); - - if (actions.contains(action)) - { - pFirstActionGroup->removeAction(action); - pSecondActionGroup->addAction(action); - } - } - } - } - else - { - if (!pCurrentItem->mpActionGroup) - { - // unless element is inserted between two separators, or a separator and an end of vector, use neighbouring group since it's shared - if (pPrevItem && pPrevItem->mpActionGroup) - { - pCurrentItem->mpActionGroup = pPrevItem->mpActionGroup; - } - else if (pNextItem && pNextItem->mpActionGroup) - { - pCurrentItem->mpActionGroup = pNextItem->mpActionGroup; - } - else - { - pCurrentItem->mpActionGroup = std::make_shared<QActionGroup>(nullptr); - pCurrentItem->mpActionGroup->setExclusive(true); - } - } - - // if there's also a different group after this element, merge it - if (pNextItem && pNextItem->mpActionGroup - && (pCurrentItem->mpActionGroup != pNextItem->mpActionGroup)) - { - auto pFirstCheckedAction = pCurrentItem->mpActionGroup->checkedAction(); - auto pSecondCheckedAction = pNextItem->mpActionGroup->checkedAction(); - auto actions = pNextItem->mpActionGroup->actions(); - - // first move all actions from second group to first one, and if first group already has checked action, - // and second group also has a checked action, uncheck action from second group - for (auto action : actions) - { - pNextItem->mpActionGroup->removeAction(action); - - if (pFirstCheckedAction && pSecondCheckedAction && (action == pSecondCheckedAction)) - { - action->setChecked(false); - } - - pCurrentItem->mpActionGroup->addAction(action); - } - - // now replace all pointers to second group with pointers to first group - for (unsigned idx = nPos + 1; idx < nCount; ++idx) - { - QtMenuItem* pModifiedItem = GetItemAtPos(idx); - - if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup)) - { - break; - } - - pModifiedItem->mpActionGroup = pCurrentItem->mpActionGroup; - } - } - } -} - -void QtMenu::ResetAllActionGroups() -{ - for (unsigned nItem = 0; nItem < GetItemCount(); ++nItem) - { - QtMenuItem* pSalMenuItem = GetItemAtPos(nItem); - pSalMenuItem->mpActionGroup.reset(); - } -} - -void QtMenu::UpdateActionGroupItem(const QtMenuItem* pSalMenuItem) -{ - QAction* pAction = pSalMenuItem->getAction(); - if (!pAction) - return; - - bool bChecked = mpVCLMenu->IsItemChecked(pSalMenuItem->mnId); - MenuItemBits itemBits = mpVCLMenu->GetItemBits(pSalMenuItem->mnId); - - if (itemBits & MenuItemBits::RADIOCHECK) - { - pAction->setCheckable(true); - - if (pSalMenuItem->mpActionGroup) - { - pSalMenuItem->mpActionGroup->addAction(pAction); - } - - pAction->setChecked(bChecked); - } - else - { - pAction->setActionGroup(nullptr); - - if (itemBits & MenuItemBits::CHECKABLE) - { - pAction->setCheckable(true); - pAction->setChecked(bChecked); - } - else - { - pAction->setChecked(false); - pAction->setCheckable(false); - } - } -} - -void QtMenu::InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos) -{ - SolarMutexGuard aGuard; - QtMenuItem* pItem = static_cast<QtMenuItem*>(pSalMenuItem); - - if (nPos == MENU_APPEND) - maItems.push_back(pItem); - else - maItems.insert(maItems.begin() + nPos, pItem); - - pItem->mpParentMenu = this; - - InsertMenuItem(pItem, nPos); -} - -void QtMenu::RemoveItem(unsigned nPos) -{ - SolarMutexGuard aGuard; - - if (nPos >= maItems.size()) - return; - - QtMenuItem* pItem = maItems[nPos]; - pItem->mpAction.reset(); - pItem->mpMenu.reset(); - - maItems.erase(maItems.begin() + nPos); - - // Recalculate action groups if necessary: - // if separator between two QActionGroups was removed, - // it may be needed to merge them - if (nPos > 0) - { - ReinitializeActionGroup(nPos - 1); - } -} - -void QtMenu::SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos) -{ - SolarMutexGuard aGuard; - QtMenuItem* pItem = static_cast<QtMenuItem*>(pSalMenuItem); - QtMenu* pQSubMenu = static_cast<QtMenu*>(pSubMenu); - - pItem->mpSubMenu = pQSubMenu; - // at this point the pointer to parent menu may be outdated, update it too - pItem->mpParentMenu = this; - - if (pQSubMenu != nullptr) - { - pQSubMenu->mpParentSalMenu = this; - pQSubMenu->mpQMenu = pItem->mpMenu.get(); - } - - // if it's not a menu bar item, then convert it to corresponding item if type if necessary. - // If submenu is present and it's an action, convert it to menu. - // If submenu is not present and it's a menu, convert it to action. - // It may be fine to proceed in any case, but by skipping other cases - // amount of unneeded actions taken should be reduced. - if (pItem->mpParentMenu->mbMenuBar || (pQSubMenu && pItem->mpMenu) - || ((!pQSubMenu) && pItem->mpAction)) - { - return; - } - - InsertMenuItem(pItem, nPos); -} - -void QtMenu::SetFrame(const SalFrame* pFrame) -{ - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - if (!pSalInst->IsMainThread()) - { - pSalInst->RunInMainThread([this, pFrame]() { SetFrame(pFrame); }); - return; - } - - SolarMutexGuard aGuard; - assert(mbMenuBar); - mpFrame = const_cast<QtFrame*>(static_cast<const QtFrame*>(pFrame)); - - mpFrame->SetMenu(this); - - QtMainWindow* pMainWindow = mpFrame->GetTopLevelWindow(); - if (!pMainWindow) - return; - - mpQMenuBar = pMainWindow->menuBar(); - if (mpQMenuBar) - { - mpQMenuBar->clear(); - QPushButton* pButton - = static_cast<QPushButton*>(mpQMenuBar->cornerWidget(Qt::TopRightCorner)); - if (pButton && ((mpCloseButton != pButton) || !maCloseButtonConnection)) - { - maCloseButtonConnection - = connect(pButton, &QPushButton::clicked, this, &QtMenu::slotCloseDocument); - mpCloseButton = pButton; - } - } - - mpQMenu = nullptr; - - DoFullMenuUpdate(mpVCLMenu); -} - -void QtMenu::DoFullMenuUpdate(Menu* pMenuBar) -{ - // clear action groups since menu is rebuilt - ResetAllActionGroups(); - ShowCloseButton(false); - - for (sal_Int32 nItem = 0; nItem < static_cast<sal_Int32>(GetItemCount()); nItem++) - { - QtMenuItem* pSalMenuItem = GetItemAtPos(nItem); - InsertMenuItem(pSalMenuItem, nItem); - SetItemImage(nItem, pSalMenuItem, pSalMenuItem->maImage); - const bool bShowDisabled - = bool(pMenuBar->GetMenuFlags() & MenuFlags::AlwaysShowDisabledEntries) - || !bool(pMenuBar->GetMenuFlags() & MenuFlags::HideDisabledEntries); - const bool bVisible = bShowDisabled || mpVCLMenu->IsItemEnabled(pSalMenuItem->mnId); - pSalMenuItem->getAction()->setVisible(bVisible); - - if (pSalMenuItem->mpSubMenu != nullptr) - { - pMenuBar->HandleMenuActivateEvent(pSalMenuItem->mpSubMenu->GetMenu()); - pSalMenuItem->mpSubMenu->DoFullMenuUpdate(pMenuBar); - pMenuBar->HandleMenuDeActivateEvent(pSalMenuItem->mpSubMenu->GetMenu()); - } - } -} - -void QtMenu::ShowItem(unsigned nPos, bool bShow) -{ - if (nPos < maItems.size()) - { - QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); - QAction* pAction = pSalMenuItem->getAction(); - if (pAction) - pAction->setVisible(bShow); - pSalMenuItem->mbVisible = bShow; - } -} - -void QtMenu::SetItemBits(unsigned nPos, MenuItemBits) -{ - if (nPos < maItems.size()) - { - QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); - UpdateActionGroupItem(pSalMenuItem); - } -} - -void QtMenu::CheckItem(unsigned nPos, bool bChecked) -{ - if (nPos < maItems.size()) - { - QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); - QAction* pAction = pSalMenuItem->getAction(); - if (pAction) - { - pAction->setCheckable(true); - pAction->setChecked(bChecked); - } - } -} - -void QtMenu::EnableItem(unsigned nPos, bool bEnable) -{ - if (nPos < maItems.size()) - { - QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); - QAction* pAction = pSalMenuItem->getAction(); - if (pAction) - pAction->setEnabled(bEnable); - pSalMenuItem->mbEnabled = bEnable; - } -} - -void QtMenu::SetItemText(unsigned, SalMenuItem* pItem, const OUString& rText) -{ - QtMenuItem* pSalMenuItem = static_cast<QtMenuItem*>(pItem); - QAction* pAction = pSalMenuItem->getAction(); - if (pAction) - { - OUString aText(rText); - NativeItemText(aText); - pAction->setText(toQString(aText)); - } -} - -void QtMenu::SetItemImage(unsigned, SalMenuItem* pItem, const Image& rImage) -{ - QtMenuItem* pSalMenuItem = static_cast<QtMenuItem*>(pItem); - - // Save new image to use it in DoFullMenuUpdate - pSalMenuItem->maImage = rImage; - - QAction* pAction = pSalMenuItem->getAction(); - if (!pAction) - return; - - pAction->setIcon(QPixmap::fromImage(toQImage(rImage))); -} - -void QtMenu::SetAccelerator(unsigned, SalMenuItem* pItem, const vcl::KeyCode&, - const OUString& rText) -{ - QtMenuItem* pSalMenuItem = static_cast<QtMenuItem*>(pItem); - QAction* pAction = pSalMenuItem->getAction(); - if (pAction) - pAction->setShortcut(QKeySequence(toQString(rText), QKeySequence::PortableText)); -} - -void QtMenu::GetSystemMenuData(SystemMenuData*) {} - -QtMenu* QtMenu::GetTopLevel() -{ - QtMenu* pMenu = this; - while (pMenu->mpParentSalMenu) - pMenu = pMenu->mpParentSalMenu; - return pMenu; -} - -void QtMenu::ShowMenuBar(bool bVisible) -{ - if (mpQMenuBar) - mpQMenuBar->setVisible(bVisible); -} - -const QtFrame* QtMenu::GetFrame() const -{ - SolarMutexGuard aGuard; - const QtMenu* pMenu = this; - while (pMenu && !pMenu->mpFrame) - pMenu = pMenu->mpParentSalMenu; - return pMenu ? pMenu->mpFrame : nullptr; -} - -void QtMenu::slotMenuTriggered(QtMenuItem* pQItem) -{ - if (!pQItem) - return; - - QtMenu* pSalMenu = pQItem->mpParentMenu; - QtMenu* pTopLevel = pSalMenu->GetTopLevel(); - - Menu* pMenu = pSalMenu->GetMenu(); - auto mnId = pQItem->mnId; - - // HACK to allow HandleMenuCommandEvent to "not-set" the checked button - // LO expects a signal before an item state change, so reset the check item - if (pQItem->mpAction->isCheckable() - && (!pQItem->mpActionGroup || pQItem->mpActionGroup->actions().size() <= 1)) - pQItem->mpAction->setChecked(!pQItem->mpAction->isChecked()); - pTopLevel->GetMenu()->HandleMenuCommandEvent(pMenu, mnId); -} - -void QtMenu::slotMenuAboutToShow(QtMenuItem* pQItem) -{ - if (pQItem) - { - QtMenu* pSalMenu = pQItem->mpSubMenu; - QtMenu* pTopLevel = pSalMenu->GetTopLevel(); - - Menu* pMenu = pSalMenu->GetMenu(); - - // following function may update the menu - pTopLevel->GetMenu()->HandleMenuActivateEvent(pMenu); - } -} - -void QtMenu::slotMenuAboutToHide(QtMenuItem* pQItem) -{ - if (pQItem) - { - QtMenu* pSalMenu = pQItem->mpSubMenu; - QtMenu* pTopLevel = pSalMenu->GetTopLevel(); - - Menu* pMenu = pSalMenu->GetMenu(); - - pTopLevel->GetMenu()->HandleMenuDeActivateEvent(pMenu); - } -} - -void QtMenu::NativeItemText(OUString& rItemText) -{ - // preserve literal '&'s in menu texts - rItemText = rItemText.replaceAll("&", "&&"); - - rItemText = rItemText.replace('~', '&'); -} - -void QtMenu::slotCloseDocument() -{ - MenuBar* pVclMenuBar = static_cast<MenuBar*>(mpVCLMenu.get()); - if (pVclMenuBar) - Application::PostUserEvent(pVclMenuBar->GetCloseButtonClickHdl()); -} - -void QtMenu::ShowCloseButton(bool bShow) -{ - if (!mpQMenuBar) - return; - - QPushButton* pButton = static_cast<QPushButton*>(mpQMenuBar->cornerWidget(Qt::TopRightCorner)); - if (!pButton) - { - QIcon aIcon; - if (QIcon::hasThemeIcon("window-close-symbolic")) - aIcon = QIcon::fromTheme("window-close-symbolic"); - else - aIcon = QIcon( - QPixmap::fromImage(toQImage(Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC)))); - pButton = new QPushButton(mpQMenuBar); - pButton->setIcon(aIcon); - pButton->setFlat(true); - pButton->setFocusPolicy(Qt::NoFocus); - pButton->setToolTip(toQString(VclResId(SV_HELPTEXT_CLOSEDOCUMENT))); - mpQMenuBar->setCornerWidget(pButton, Qt::TopRightCorner); - maCloseButtonConnection - = connect(pButton, &QPushButton::clicked, this, &QtMenu::slotCloseDocument); - mpCloseButton = pButton; - } - - if (bShow) - pButton->show(); - else - pButton->hide(); -} - -bool QtMenu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&, - FloatWinPopupFlags nFlags) -{ - assert(mpQMenu); - DoFullMenuUpdate(mpVCLMenu); - mpQMenu->setTearOffEnabled(bool(nFlags & FloatWinPopupFlags::AllowTearOff)); - - const QPoint aPos = QCursor::pos(); - mpQMenu->exec(aPos); - - return true; -} - -QtMenuItem::QtMenuItem(const SalItemParams* pItemData) - : mpParentMenu(nullptr) - , mpSubMenu(nullptr) - , mnId(pItemData->nId) - , mnType(pItemData->eType) - , mbVisible(true) - , mbEnabled(true) - , maImage(pItemData->aImage) -{ -} - -QAction* QtMenuItem::getAction() const -{ - if (mpMenu) - return mpMenu->menuAction(); - if (mpAction) - return mpAction.get(); - return nullptr; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Object.cxx b/vcl/qt5/Qt5Object.cxx deleted file mode 100644 index b48c1a143248..000000000000 --- a/vcl/qt5/Qt5Object.cxx +++ /dev/null @@ -1,157 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Object.hxx> -#include <Qt5Object.moc> - -#include <Qt5Frame.hxx> -#include <Qt5Widget.hxx> - -#include <QtGui/QGuiApplication> - -QtObject::QtObject(QtFrame* pParent, bool bShow) - : m_pParent(pParent) - , m_pQWidget(nullptr) - , m_pQWindow(nullptr) -{ - if (!m_pParent || !pParent->GetQWidget()) - return; - - m_pQWindow = new QtObjectWindow(*this); - m_pQWidget = QWidget::createWindowContainer(m_pQWindow, pParent->GetQWidget()); - m_pQWidget->setAttribute(Qt::WA_NoSystemBackground); - connect(m_pQWidget, &QObject::destroyed, this, [this]() { m_pQWidget = nullptr; }); - - if (bShow) - m_pQWidget->show(); - - m_aSystemData.aShellWindow = reinterpret_cast<sal_IntPtr>(this); - //m_aSystemData.pSalFrame = this; - m_aSystemData.pWidget = m_pQWidget; - //m_aSystemData.nScreen = m_nXScreen.getXScreen(); - m_aSystemData.toolkit = SystemEnvData::Toolkit::Qt5; - m_aSystemData.platform = SystemEnvData::Platform::Xcb; - const bool bWayland = QGuiApplication::platformName() == "wayland"; - if (!bWayland) - { - m_aSystemData.platform = SystemEnvData::Platform::Xcb; - m_aSystemData.SetWindowHandle(m_pQWindow->winId()); // ID of the embedded window - } - else - { - m_aSystemData.platform = SystemEnvData::Platform::Wayland; - // TODO implement as needed for Wayland, - // s.a. commit c0d4f3ad3307c which did this for gtk3 - // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface(); - // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr); - // m_aSystemData.aWindow = reinterpret_cast<unsigned long>( - // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle())); - } -} - -QtObject::~QtObject() -{ - if (m_pQWidget) - { - m_pQWidget->setParent(nullptr); - delete m_pQWidget; - } -} - -void QtObject::ResetClipRegion() -{ - if (m_pQWidget) - m_pRegion = QRegion(m_pQWidget->geometry()); - else - m_pRegion = QRegion(); -} - -void QtObject::BeginSetClipRegion(sal_uInt32) { m_pRegion = QRegion(); } - -void QtObject::UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) -{ - m_pRegion += QRect(nX, nY, nWidth, nHeight); -} - -void QtObject::EndSetClipRegion() -{ - if (m_pQWidget) - m_pRegion = m_pRegion.intersected(m_pQWidget->geometry()); -} - -void QtObject::SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight) -{ - if (m_pQWidget) - { - m_pQWidget->move(nX, nY); - m_pQWidget->setFixedSize(nWidth, nHeight); - } -} - -void QtObject::Show(bool bVisible) -{ - if (m_pQWidget) - m_pQWidget->setVisible(bVisible); -} - -void QtObject::SetForwardKey(bool /*bEnable*/) {} - -QtObjectWindow::QtObjectWindow(QtObject& rParent) - : m_rParent(rParent) -{ - assert(m_rParent.frame() && m_rParent.frame()->GetQWidget()); -} - -void QtObjectWindow::focusInEvent(QFocusEvent* pEvent) -{ - m_rParent.CallCallback(SalObjEvent::GetFocus); - QWindow::focusInEvent(pEvent); -} - -void QtObjectWindow::focusOutEvent(QFocusEvent* pEvent) -{ - m_rParent.CallCallback(SalObjEvent::LoseFocus); - QWindow::focusOutEvent(pEvent); -} - -void QtObjectWindow::mousePressEvent(QMouseEvent* pEvent) -{ - m_rParent.CallCallback(SalObjEvent::ToTop); - QtWidget::handleMousePressEvent(*m_rParent.frame(), pEvent); -} - -void QtObjectWindow::mouseReleaseEvent(QMouseEvent* pEvent) -{ - QtWidget::handleMouseReleaseEvent(*m_rParent.frame(), pEvent); -} - -bool QtObjectWindow::event(QEvent* pEvent) -{ - return QtWidget::handleEvent(*m_rParent.frame(), *m_rParent.widget(), pEvent) - || QWindow::event(pEvent); -} - -void QtObjectWindow::keyReleaseEvent(QKeyEvent* pEvent) -{ - if (!QtWidget::handleKeyReleaseEvent(*m_rParent.frame(), *m_rParent.widget(), pEvent)) - QWindow::keyReleaseEvent(pEvent); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5OpenGLContext.cxx b/vcl/qt5/Qt5OpenGLContext.cxx deleted file mode 100644 index 0c8dd1729886..000000000000 --- a/vcl/qt5/Qt5OpenGLContext.cxx +++ /dev/null @@ -1,154 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5OpenGLContext.hxx> - -#include <epoxy/gl.h> - -#include <vcl/sysdata.hxx> -#include <opengl/zone.hxx> -#include <sal/log.hxx> - -#include <window.h> - -#include <Qt5Object.hxx> - -#include <QtGui/QOpenGLContext> -#include <QtGui/QWindow> - -bool QtOpenGLContext::g_bAnyCurrent = false; - -void QtOpenGLContext::swapBuffers() -{ - OpenGLZone aZone; - - if (m_pContext && m_pWindow && m_pWindow->isExposed()) - { - m_pContext->swapBuffers(m_pWindow); - } - - BuffersSwapped(); -} - -void QtOpenGLContext::resetCurrent() -{ - clearCurrent(); - - OpenGLZone aZone; - - if (m_pContext) - { - m_pContext->doneCurrent(); - g_bAnyCurrent = false; - } -} - -bool QtOpenGLContext::isCurrent() -{ - OpenGLZone aZone; - return g_bAnyCurrent && (QOpenGLContext::currentContext() == m_pContext); -} - -bool QtOpenGLContext::isAnyCurrent() -{ - OpenGLZone aZone; - return g_bAnyCurrent && (QOpenGLContext::currentContext() != nullptr); -} - -bool QtOpenGLContext::ImplInit() -{ - if (!m_pWindow) - { - SAL_WARN("vcl.opengl.qt5", "failed to create window"); - return false; - } - - m_pWindow->setSurfaceType(QSurface::OpenGLSurface); - m_pWindow->create(); - - m_pContext = new QOpenGLContext(m_pWindow); - if (!m_pContext->create()) - { - SAL_WARN("vcl.opengl.qt5", "failed to create context"); - return false; - } - - m_pContext->makeCurrent(m_pWindow); - g_bAnyCurrent = true; - - bool bRet = InitGL(); - InitGLDebugging(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - registerAsCurrent(); - - return bRet; -} - -void QtOpenGLContext::makeCurrent() -{ - if (isCurrent()) - return; - - OpenGLZone aZone; - - clearCurrent(); - - if (m_pContext && m_pWindow) - { - m_pContext->makeCurrent(m_pWindow); - g_bAnyCurrent = true; - } - - registerAsCurrent(); -} - -void QtOpenGLContext::destroyCurrentContext() -{ - OpenGLZone aZone; - - if (m_pContext) - { - m_pContext->doneCurrent(); - g_bAnyCurrent = false; - } - - if (glGetError() != GL_NO_ERROR) - { - SAL_WARN("vcl.opengl.qt5", "glError: " << glGetError()); - } -} - -void QtOpenGLContext::initWindow() -{ - if (!m_pChildWindow) - { - SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); - m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); - } - - if (m_pChildWindow) - { - InitChildWindow(m_pChildWindow.get()); - } - - m_pWindow - = static_cast<QtObject*>(m_pChildWindow->ImplGetWindowImpl()->mpSysObj)->windowHandle(); -} diff --git a/vcl/qt5/Qt5Painter.cxx b/vcl/qt5/Qt5Painter.cxx deleted file mode 100644 index 5941b3dbeabb..000000000000 --- a/vcl/qt5/Qt5Painter.cxx +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Painter.hxx> - -#include <QtGui/QColor> - -QtPainter::QtPainter(QtGraphicsBackend& rGraphics, bool bPrepareBrush, sal_uInt8 nTransparency) - : m_rGraphics(rGraphics) -{ - if (rGraphics.m_pQImage) - { - if (!begin(rGraphics.m_pQImage)) - std::abort(); - } - else - { - assert(rGraphics.m_pFrame); - if (!begin(rGraphics.m_pFrame->GetQWidget())) - std::abort(); - } - if (!rGraphics.m_aClipPath.isEmpty()) - setClipPath(rGraphics.m_aClipPath); - else - setClipRegion(rGraphics.m_aClipRegion); - if (SALCOLOR_NONE != rGraphics.m_aLineColor) - { - QColor aColor = toQColor(rGraphics.m_aLineColor); - aColor.setAlpha(nTransparency); - setPen(aColor); - } - else - setPen(Qt::NoPen); - if (bPrepareBrush && SALCOLOR_NONE != rGraphics.m_aFillColor) - { - QColor aColor = toQColor(rGraphics.m_aFillColor); - aColor.setAlpha(nTransparency); - setBrush(aColor); - } - setCompositionMode(rGraphics.m_eCompositionMode); -} diff --git a/vcl/qt5/Qt5Printer.cxx b/vcl/qt5/Qt5Printer.cxx deleted file mode 100644 index 3f77fce307ec..000000000000 --- a/vcl/qt5/Qt5Printer.cxx +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Printer.hxx> - -QtPrinter::QtPrinter(SalInfoPrinter* pInfoPrinter) - : PspSalPrinter(pInfoPrinter) -{ -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5SvpGraphics.cxx b/vcl/qt5/Qt5SvpGraphics.cxx deleted file mode 100644 index 1d2b4dc7de1a..000000000000 --- a/vcl/qt5/Qt5SvpGraphics.cxx +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <sal/log.hxx> -#include <salbmp.hxx> - -#include <config_cairo_canvas.h> - -#include <Qt5Data.hxx> -#include <Qt5Frame.hxx> -#include <Qt5Graphics_Controls.hxx> -#include <Qt5SvpGraphics.hxx> -#include <Qt5SvpSurface.hxx> -#include <Qt5Tools.hxx> - -#include <QtGui/QScreen> -#include <QtGui/QWindow> -#include <QtWidgets/QWidget> - -QtSvpGraphics::QtSvpGraphics(QtFrame* pFrame) - : m_pFrame(pFrame) -{ - if (!QtData::noNativeControls()) - m_pWidgetDraw.reset(new QtGraphics_Controls(*this)); - if (m_pFrame) - setDevicePixelRatioF(m_pFrame->devicePixelRatioF()); -} - -QtSvpGraphics::~QtSvpGraphics() {} - -void QtSvpGraphics::updateQWidget() const -{ - if (!m_pFrame) - return; - QWidget* pQWidget = m_pFrame->GetQWidget(); - if (pQWidget) - pQWidget->update(pQWidget->rect()); -} - -#if ENABLE_CAIRO_CANVAS - -bool QtSvpGraphics::SupportsCairo() const { return true; } - -cairo::SurfaceSharedPtr -QtSvpGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const -{ - return std::make_shared<cairo::QtSvpSurface>(rSurface); -} - -cairo::SurfaceSharedPtr QtSvpGraphics::CreateSurface(const OutputDevice& /*rRefDevice*/, int x, - int y, int width, int height) const -{ - return std::make_shared<cairo::QtSvpSurface>(this, x, y, width, height); -} - -#endif - -static void QImage2BitmapBuffer(QImage& rImg, BitmapBuffer& rBuf) -{ - assert(rImg.width()); - assert(rImg.height()); - - rBuf.mnWidth = rImg.width(); - rBuf.mnHeight = rImg.height(); - rBuf.mnBitCount = getFormatBits(rImg.format()); - rBuf.mpBits = rImg.bits(); - rBuf.mnScanlineSize = rImg.bytesPerLine(); -} - -void QtSvpGraphics::handleDamage(const tools::Rectangle& rDamagedRegion) -{ - assert(m_pWidgetDraw); - assert(dynamic_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())); - assert(!rDamagedRegion.IsEmpty()); - - QImage* pImage = static_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())->getImage(); - assert(pImage); - if (pImage->width() == 0 || pImage->height() == 0) - return; - - BitmapBuffer aBuffer; - QImage2BitmapBuffer(*pImage, aBuffer); - SalTwoRect aTR(0, 0, pImage->width(), pImage->height(), rDamagedRegion.Left(), - rDamagedRegion.Top(), rDamagedRegion.GetWidth(), rDamagedRegion.GetHeight()); - drawBitmap(aTR, &aBuffer, CAIRO_OPERATOR_OVER); -} - -void QtSvpGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) -{ - char* pForceDpi; - if ((pForceDpi = getenv("SAL_FORCEDPI"))) - { - OString sForceDPI(pForceDpi); - rDPIX = rDPIY = sForceDPI.toInt32(); - return; - } - - if (!m_pFrame || !m_pFrame->GetQWidget()->window()->windowHandle()) - return; - - QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen(); - rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5; - rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5SvpSurface.cxx b/vcl/qt5/Qt5SvpSurface.cxx deleted file mode 100644 index 8b83e9f98424..000000000000 --- a/vcl/qt5/Qt5SvpSurface.cxx +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <utility> - -#include <Qt5SvpSurface.hxx> - -#include <Qt5SvpGraphics.hxx> - -#include <vcl/sysdata.hxx> -#include <vcl/bitmap.hxx> -#include <vcl/virdev.hxx> -#include <vcl/window.hxx> -#include <basegfx/vector/b2isize.hxx> - -namespace -{ -Size get_surface_size(cairo_surface_t* surface) -{ - cairo_t* cr = cairo_create(surface); - double x1, x2, y1, y2; - cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - cairo_destroy(cr); - return Size(x2 - x1, y2 - y1); -} -} - -namespace cairo -{ -QtSvpSurface::QtSvpSurface(const CairoSurfaceSharedPtr& pSurface) - : m_pGraphics(nullptr) - , m_pCairoContext(nullptr) - , m_pSurface(pSurface) -{ -} - -QtSvpSurface::QtSvpSurface(const QtSvpGraphics* pGraphics, int x, int y, int width, int height) - : m_pGraphics(pGraphics) - , m_pCairoContext(pGraphics->getCairoContext(false)) -{ - cairo_surface_t* surface = cairo_get_target(m_pCairoContext); - m_pSurface.reset(cairo_surface_create_for_rectangle(surface, x, y, width, height), - &cairo_surface_destroy); -} - -QtSvpSurface::~QtSvpSurface() -{ - if (m_pCairoContext) - cairo_destroy(m_pCairoContext); -} - -CairoSharedPtr QtSvpSurface::getCairo() const -{ - return CairoSharedPtr(cairo_create(m_pSurface.get()), &cairo_destroy); -} - -SurfaceSharedPtr QtSvpSurface::getSimilar(int cairo_content_type, int width, int height) const -{ - return std::make_shared<QtSvpSurface>(CairoSurfaceSharedPtr( - cairo_surface_create_similar( - m_pSurface.get(), static_cast<cairo_content_t>(cairo_content_type), width, height), - &cairo_surface_destroy)); -} - -void QtSvpSurface::flush() const -{ - cairo_surface_flush(m_pSurface.get()); - if (m_pGraphics) - m_pGraphics->updateQWidget(); -} - -VclPtr<VirtualDevice> QtSvpSurface::createVirtualDevice() const -{ - SystemGraphicsData aSystemGraphicsData; - - aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); - aSystemGraphicsData.pSurface = m_pSurface.get(); - - return VclPtr<VirtualDevice>::Create(aSystemGraphicsData, get_surface_size(m_pSurface.get()), - DeviceFormat::DEFAULT); -} - -} // namespace cairo - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5SvpVirtualDevice.hxx b/vcl/qt5/Qt5SvpVirtualDevice.hxx deleted file mode 100644 index 8d9dcdc20d72..000000000000 --- a/vcl/qt5/Qt5SvpVirtualDevice.hxx +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <headless/svpvd.hxx> -#include <Qt5SvpGraphics.hxx> - -class VCL_DLLPUBLIC QtSvpVirtualDevice : public SvpSalVirtualDevice -{ -public: - QtSvpVirtualDevice(cairo_surface_t* pRefSurface, cairo_surface_t* pPreExistingTarget) - : SvpSalVirtualDevice(pRefSurface, pPreExistingTarget) - { - } - - SalGraphics* AcquireGraphics() override { return AddGraphics(new QtSvpGraphics(nullptr)); } -}; - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5System.cxx b/vcl/qt5/Qt5System.cxx deleted file mode 100644 index 7483850a28e7..000000000000 --- a/vcl/qt5/Qt5System.cxx +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <QtGui/QGuiApplication> -#include <QtGui/QScreen> - -#include <tools/gen.hxx> -#include <Qt5System.hxx> -#include <Qt5Tools.hxx> - -unsigned int QtSystem::GetDisplayScreenCount() { return QGuiApplication::screens().size(); } - -tools::Rectangle QtSystem::GetDisplayScreenPosSizePixel(unsigned int nScreen) -{ - QRect qRect = QGuiApplication::screens().at(nScreen)->geometry(); - return toRectangle(scaledQRect(qRect, qApp->devicePixelRatio())); -} - -int QtSystem::ShowNativeDialog(const OUString&, const OUString&, const std::vector<OUString>&) -{ - return 0; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Timer.cxx b/vcl/qt5/Qt5Timer.cxx deleted file mode 100644 index f52491d81cd0..000000000000 --- a/vcl/qt5/Qt5Timer.cxx +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Timer.hxx> -#include <Qt5Timer.moc> - -#include <QtWidgets/QApplication> -#include <QtCore/QThread> - -#include <vcl/svapp.hxx> -#include <sal/log.hxx> - -QtTimer::QtTimer() -{ - m_aTimer.setSingleShot(true); - m_aTimer.setTimerType(Qt::PreciseTimer); - connect(&m_aTimer, SIGNAL(timeout()), this, SLOT(timeoutActivated())); - connect(this, SIGNAL(startTimerSignal(int)), this, SLOT(startTimer(int))); - connect(this, SIGNAL(stopTimerSignal()), this, SLOT(stopTimer())); -} - -void QtTimer::timeoutActivated() -{ - SolarMutexGuard aGuard; - CallCallback(); -} - -void QtTimer::startTimer(int nMS) { m_aTimer.start(nMS); } - -void QtTimer::Start(sal_uInt64 nMS) { Q_EMIT startTimerSignal(nMS); } - -void QtTimer::stopTimer() { m_aTimer.stop(); } - -void QtTimer::Stop() { Q_EMIT stopTimerSignal(); } - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Tools.cxx b/vcl/qt5/Qt5Tools.cxx deleted file mode 100644 index 6642c66af0cf..000000000000 --- a/vcl/qt5/Qt5Tools.cxx +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Tools.hxx> - -#include <cairo.h> - -#include <tools/stream.hxx> -#include <vcl/event.hxx> -#include <vcl/image.hxx> -#include <vcl/pngwrite.hxx> - -#include <QtGui/QImage> - -void CairoDeleter::operator()(cairo_surface_t* pSurface) const { cairo_surface_destroy(pSurface); } - -sal_uInt16 GetKeyModCode(Qt::KeyboardModifiers eKeyModifiers) -{ - sal_uInt16 nCode = 0; - if (eKeyModifiers & Qt::ShiftModifier) - nCode |= KEY_SHIFT; - if (eKeyModifiers & Qt::ControlModifier) - nCode |= KEY_MOD1; - if (eKeyModifiers & Qt::AltModifier) - nCode |= KEY_MOD2; - if (eKeyModifiers & Qt::MetaModifier) - nCode |= KEY_MOD3; - return nCode; -} - -sal_uInt16 GetMouseModCode(Qt::MouseButtons eButtons) -{ - sal_uInt16 nCode = 0; - if (eButtons & Qt::LeftButton) - nCode |= MOUSE_LEFT; - if (eButtons & Qt::MiddleButton) - nCode |= MOUSE_MIDDLE; - if (eButtons & Qt::RightButton) - nCode |= MOUSE_RIGHT; - return nCode; -} - -Qt::DropActions toQtDropActions(sal_Int8 dragOperation) -{ - Qt::DropActions eRet = Qt::IgnoreAction; - if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) - eRet |= Qt::CopyAction; - if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) - eRet |= Qt::MoveAction; - if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) - eRet |= Qt::LinkAction; - return eRet; -} - -sal_Int8 toVclDropActions(Qt::DropActions dragOperation) -{ - sal_Int8 nRet(0); - if (dragOperation & Qt::CopyAction) - nRet |= css::datatransfer::dnd::DNDConstants::ACTION_COPY; - if (dragOperation & Qt::MoveAction) - nRet |= css::datatransfer::dnd::DNDConstants::ACTION_MOVE; - if (dragOperation & Qt::LinkAction) - nRet |= css::datatransfer::dnd::DNDConstants::ACTION_LINK; - return nRet; -} - -sal_Int8 toVclDropAction(Qt::DropAction dragOperation) -{ - sal_Int8 nRet(0); - if (dragOperation == Qt::CopyAction) - nRet = css::datatransfer::dnd::DNDConstants::ACTION_COPY; - else if (dragOperation == Qt::MoveAction) - nRet = css::datatransfer::dnd::DNDConstants::ACTION_MOVE; - else if (dragOperation == Qt::LinkAction) - nRet = css::datatransfer::dnd::DNDConstants::ACTION_LINK; - return nRet; -} - -Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation) -{ - Qt::DropAction eAct = Qt::IgnoreAction; - if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) - eAct = Qt::MoveAction; - else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) - eAct = Qt::CopyAction; - else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) - eAct = Qt::LinkAction; - return eAct; -} - -QImage toQImage(const Image& rImage) -{ - QImage aImage; - - if (!!rImage) - { - SvMemoryStream aMemStm; - vcl::PNGWriter aWriter(rImage.GetBitmapEx()); - aWriter.Write(aMemStm); - aImage.loadFromData(static_cast<const uchar*>(aMemStm.GetData()), aMemStm.TellEnd()); - } - - return aImage; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Transferable.cxx b/vcl/qt5/Qt5Transferable.cxx deleted file mode 100644 index 5da55fa653c1..000000000000 --- a/vcl/qt5/Qt5Transferable.cxx +++ /dev/null @@ -1,344 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <Qt5Transferable.hxx> - -#include <comphelper/sequence.hxx> -#include <sal/log.hxx> - -#include <QtWidgets/QApplication> - -#include <Qt5Instance.hxx> -#include <Qt5Tools.hxx> - -#include <cassert> - -static bool lcl_textMimeInfo(const OUString& rMimeString, bool& bHaveNoCharset, bool& bHaveUTF16, - bool& bHaveUTF8) -{ - sal_Int32 nIndex = 0; - if (rMimeString.getToken(0, ';', nIndex) == "text/plain") - { - OUString aToken(rMimeString.getToken(0, ';', nIndex)); - if (aToken == "charset=utf-16") - bHaveUTF16 = true; - else if (aToken == "charset=utf-8") - bHaveUTF8 = true; - else if (aToken.isEmpty()) - bHaveNoCharset = true; - else // we just handle UTF-16 and UTF-8, everything else is "bytes" - return false; - return true; - } - return false; -} - -QtTransferable::QtTransferable(const QMimeData* pMimeData) - : m_pMimeData(pMimeData) - , m_bConvertFromLocale(false) -{ - assert(pMimeData); -} - -css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL QtTransferable::getTransferDataFlavors() -{ - // it's just filled once, ever, so just try to get it without locking first - if (m_aMimeTypeSeq.hasElements()) - return m_aMimeTypeSeq; - - // better safe then sorry; preventing broken usage - // DnD should not be shared and Clipboard access runs in the GUI thread - osl::MutexGuard aGuard(m_aMutex); - if (m_aMimeTypeSeq.hasElements()) - return m_aMimeTypeSeq; - - QStringList aFormatList(m_pMimeData->formats()); - // we might add the UTF-16 mime text variant later - const int nMimeTypeSeqSize = aFormatList.size() + 1; - bool bHaveNoCharset = false, bHaveUTF16 = false; - css::uno::Sequence<css::datatransfer::DataFlavor> aMimeTypeSeq(nMimeTypeSeqSize); - - css::datatransfer::DataFlavor aFlavor; - int nMimeTypeCount = 0; - - for (const QString& rMimeType : aFormatList) - { - // filter out non-MIME types such as TARGETS, MULTIPLE, TIMESTAMP - if (rMimeType.indexOf('/') == -1) - continue; - - // gtk3 thinks it is not well defined - skip too - if (rMimeType == QStringLiteral("text/plain;charset=unicode")) - continue; - - // LO doesn't like 'text/plain', so we have to provide UTF-16 - bool bIsNoCharset = false, bIsUTF16 = false, bIsUTF8 = false; - if (lcl_textMimeInfo(toOUString(rMimeType), bIsNoCharset, bIsUTF16, bIsUTF8)) - { - bHaveNoCharset |= bIsNoCharset; - bHaveUTF16 |= bIsUTF16; - if (bIsUTF16) - aFlavor.DataType = cppu::UnoType<OUString>::get(); - else - aFlavor.DataType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(); - } - else - aFlavor.DataType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(); - - aFlavor.MimeType = toOUString(rMimeType); - assert(nMimeTypeCount < nMimeTypeSeqSize); - aMimeTypeSeq[nMimeTypeCount] = aFlavor; - nMimeTypeCount++; - } - - m_bConvertFromLocale = bHaveNoCharset && !bHaveUTF16; - if (m_bConvertFromLocale) - { - aFlavor.MimeType = "text/plain;charset=utf-16"; - aFlavor.DataType = cppu::UnoType<OUString>::get(); - assert(nMimeTypeCount < nMimeTypeSeqSize); - aMimeTypeSeq[nMimeTypeCount] = aFlavor; - nMimeTypeCount++; - } - - aMimeTypeSeq.realloc(nMimeTypeCount); - - m_aMimeTypeSeq = aMimeTypeSeq; - return m_aMimeTypeSeq; -} - -sal_Bool SAL_CALL -QtTransferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) -{ - const auto aSeq = getTransferDataFlavors(); - return std::any_of(aSeq.begin(), aSeq.end(), [&](const css::datatransfer::DataFlavor& aFlavor) { - return rFlavor.MimeType == aFlavor.MimeType; - }); -} - -css::uno::Any SAL_CALL QtTransferable::getTransferData(const css::datatransfer::DataFlavor& rFlavor) -{ - css::uno::Any aAny; - if (!isDataFlavorSupported(rFlavor)) - return aAny; - - if (rFlavor.MimeType == "text/plain;charset=utf-16") - { - OUString aString; - if (m_bConvertFromLocale) - { - QByteArray aByteData(m_pMimeData->data(QStringLiteral("text/plain"))); - aString = OUString(reinterpret_cast<const char*>(aByteData.data()), aByteData.size(), - osl_getThreadTextEncoding()); - } - else - { - QByteArray aByteData(m_pMimeData->data(toQString(rFlavor.MimeType))); - aString = OUString(reinterpret_cast<const sal_Unicode*>(aByteData.data()), - aByteData.size() / 2); - } - aAny <<= aString; - } - else - { - QByteArray aByteData(m_pMimeData->data(toQString(rFlavor.MimeType))); - css::uno::Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(aByteData.data()), - aByteData.size()); - aAny <<= aSeq; - } - - return aAny; -} - -QtClipboardTransferable::QtClipboardTransferable(const QClipboard::Mode aMode, - const QMimeData* pMimeData) - : QtTransferable(pMimeData) - , m_aMode(aMode) -{ -} - -bool QtClipboardTransferable::hasInFlightChanged() const -{ - const bool bChanged(mimeData() != QApplication::clipboard()->mimeData(m_aMode)); - SAL_WARN_IF(bChanged, "vcl.qt5", - "In flight clipboard change detected - broken clipboard read!"); - return bChanged; -} - -css::uno::Any SAL_CALL -QtClipboardTransferable::getTransferData(const css::datatransfer::DataFlavor& rFlavor) -{ - css::uno::Any aAny; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - SolarMutexGuard g; - pSalInst->RunInMainThread([&, this]() { - if (!hasInFlightChanged()) - aAny = QtTransferable::getTransferData(rFlavor); - }); - return aAny; -} - -css::uno::Sequence<css::datatransfer::DataFlavor> - SAL_CALL QtClipboardTransferable::getTransferDataFlavors() -{ - css::uno::Sequence<css::datatransfer::DataFlavor> aSeq; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - SolarMutexGuard g; - pSalInst->RunInMainThread([&, this]() { - if (!hasInFlightChanged()) - aSeq = QtTransferable::getTransferDataFlavors(); - }); - return aSeq; -} - -sal_Bool SAL_CALL -QtClipboardTransferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) -{ - bool bIsSupported = false; - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - SolarMutexGuard g; - pSalInst->RunInMainThread([&, this]() { - if (!hasInFlightChanged()) - bIsSupported = QtTransferable::isDataFlavorSupported(rFlavor); - }); - return bIsSupported; -} - -QtMimeData::QtMimeData(const css::uno::Reference<css::datatransfer::XTransferable>& xTrans) - : m_aContents(xTrans) - , m_bHaveNoCharset(false) - , m_bHaveUTF8(false) -{ - assert(xTrans.is()); -} - -bool QtMimeData::deepCopy(QMimeData** const pMimeCopy) const -{ - if (!pMimeCopy) - return false; - - QMimeData* pMimeData = new QMimeData(); - for (QString& format : formats()) - { - QByteArray aData = data(format); - // Checking for custom MIME types - if (format.startsWith("application/x-qt")) - { - // Retrieving true format name - int indexBegin = format.indexOf('"') + 1; - int indexEnd = format.indexOf('"', indexBegin); - format = format.mid(indexBegin, indexEnd - indexBegin); - } - pMimeData->setData(format, aData); - } - - *pMimeCopy = pMimeData; - return true; -} - -QStringList QtMimeData::formats() const -{ - if (!m_aMimeTypeList.isEmpty()) - return m_aMimeTypeList; - - const css::uno::Sequence<css::datatransfer::DataFlavor> aFormats - = m_aContents->getTransferDataFlavors(); - QStringList aList; - bool bHaveUTF16 = false; - - for (const auto& rFlavor : aFormats) - { - aList << toQString(rFlavor.MimeType); - lcl_textMimeInfo(rFlavor.MimeType, m_bHaveNoCharset, bHaveUTF16, m_bHaveUTF8); - } - - // we provide a locale encoded and a UTF-8 variant, if missing - if (m_bHaveNoCharset || bHaveUTF16 || m_bHaveUTF8) - { - // if there is a text representation from LO point of view, it'll be UTF-16 - assert(bHaveUTF16); - if (!m_bHaveUTF8) - aList << QStringLiteral("text/plain;charset=utf-8"); - if (!m_bHaveNoCharset) - aList << QStringLiteral("text/plain"); - } - - m_aMimeTypeList = aList; - return m_aMimeTypeList; -} - -QVariant QtMimeData::retrieveData(const QString& mimeType, QVariant::Type) const -{ - if (!hasFormat(mimeType)) - return QVariant(); - - css::datatransfer::DataFlavor aFlavor; - aFlavor.MimeType = toOUString(mimeType); - aFlavor.DataType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(); - - bool bWantNoCharset = false, bWantUTF16 = false, bWantUTF8 = false; - if (lcl_textMimeInfo(aFlavor.MimeType, bWantNoCharset, bWantUTF16, bWantUTF8)) - { - if ((bWantNoCharset && !m_bHaveNoCharset) || (bWantUTF8 && !m_bHaveUTF8)) - { - aFlavor.MimeType = "text/plain;charset=utf-16"; - aFlavor.DataType = cppu::UnoType<OUString>::get(); - } - else if (bWantUTF16) - aFlavor.DataType = cppu::UnoType<OUString>::get(); - } - - css::uno::Any aValue; - - try - { - // tdf#129809 take a reference in case m_aContents is replaced during this call - css::uno::Reference<com::sun::star::datatransfer::XTransferable> xCurrentContents( - m_aContents); - aValue = xCurrentContents->getTransferData(aFlavor); - } - catch (...) - { - } - - QByteArray aByteArray; - if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING) - { - OUString aString; - aValue >>= aString; - - if (bWantUTF8) - { - OString aUTF8String(OUStringToOString(aString, RTL_TEXTENCODING_UTF8)); - aByteArray = QByteArray(reinterpret_cast<const char*>(aUTF8String.getStr()), - aUTF8String.getLength()); - } - else if (bWantNoCharset) - { - OString aLocaleString(OUStringToOString(aString, osl_getThreadTextEncoding())); - aByteArray = QByteArray(reinterpret_cast<const char*>(aLocaleString.getStr()), - aLocaleString.getLength()); - } - else - return QVariant(toQString(aString)); - } - else - { - css::uno::Sequence<sal_Int8> aData; - aValue >>= aData; - aByteArray - = QByteArray(reinterpret_cast<const char*>(aData.getConstArray()), aData.getLength()); - } - return QVariant::fromValue(aByteArray); -} - -bool QtMimeData::hasFormat(const QString& mimeType) const { return formats().contains(mimeType); } - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5VirtualDevice.cxx b/vcl/qt5/Qt5VirtualDevice.cxx deleted file mode 100644 index 85f56bff4c17..000000000000 --- a/vcl/qt5/Qt5VirtualDevice.cxx +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5VirtualDevice.hxx> - -#include <Qt5Graphics.hxx> -#include <Qt5Tools.hxx> - -#include <QtGui/QImage> - -QtVirtualDevice::QtVirtualDevice(double fScale) - : m_fScale(fScale) -{ -} - -SalGraphics* QtVirtualDevice::AcquireGraphics() -{ - assert(m_pImage); - QtGraphics* pGraphics = new QtGraphics(m_pImage.get()); - m_aGraphics.push_back(pGraphics); - return pGraphics; -} - -void QtVirtualDevice::ReleaseGraphics(SalGraphics* pGraphics) -{ - m_aGraphics.erase( - std::remove(m_aGraphics.begin(), m_aGraphics.end(), dynamic_cast<QtGraphics*>(pGraphics)), - m_aGraphics.end()); - delete pGraphics; -} - -bool QtVirtualDevice::SetSize(tools::Long nNewDX, tools::Long nNewDY) -{ - return SetSizeUsingBuffer(nNewDX, nNewDY, nullptr); -} - -bool QtVirtualDevice::SetSizeUsingBuffer(tools::Long nNewDX, tools::Long nNewDY, sal_uInt8* pBuffer) -{ - if (nNewDX == 0) - nNewDX = 1; - if (nNewDY == 0) - nNewDY = 1; - - if (m_pImage && m_aFrameSize.width() == nNewDX && m_aFrameSize.height() == nNewDY) - return true; - - m_aFrameSize = QSize(nNewDX, nNewDY); - - nNewDX *= m_fScale; - nNewDY *= m_fScale; - - if (pBuffer) - m_pImage.reset(new QImage(pBuffer, nNewDX, nNewDY, Qt_DefaultFormat32)); - else - m_pImage.reset(new QImage(nNewDX, nNewDY, Qt_DefaultFormat32)); - - m_pImage->fill(Qt::transparent); - m_pImage->setDevicePixelRatio(m_fScale); - - // update device in existing graphics - for (auto pQtGraph : m_aGraphics) - pQtGraph->ChangeQImage(m_pImage.get()); - - return true; -} - -tools::Long QtVirtualDevice::GetWidth() const { return m_pImage ? m_aFrameSize.width() : 0; } - -tools::Long QtVirtualDevice::GetHeight() const { return m_pImage ? m_aFrameSize.height() : 0; } - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Widget.cxx b/vcl/qt5/Qt5Widget.cxx deleted file mode 100644 index 9eb9ac7d3ee9..000000000000 --- a/vcl/qt5/Qt5Widget.cxx +++ /dev/null @@ -1,842 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <Qt5Widget.hxx> -#include <Qt5Widget.moc> - -#include <Qt5Frame.hxx> -#include <Qt5Graphics.hxx> -#include <Qt5Instance.hxx> -#include <Qt5SvpGraphics.hxx> -#include <Qt5Transferable.hxx> -#include <Qt5Tools.hxx> - -#include <QtCore/QMimeData> -#include <QtGui/QDrag> -#include <QtGui/QFocusEvent> -#include <QtGui/QGuiApplication> -#include <QtGui/QImage> -#include <QtGui/QKeyEvent> -#include <QtGui/QMouseEvent> -#include <QtGui/QPainter> -#include <QtGui/QPaintEvent> -#include <QtGui/QResizeEvent> -#include <QtGui/QShowEvent> -#include <QtGui/QTextCharFormat> -#include <QtGui/QWheelEvent> -#include <QtWidgets/QMainWindow> -#include <QtWidgets/QWidget> - -#include <cairo.h> -#include <vcl/commandevent.hxx> -#include <vcl/event.hxx> -#include <vcl/toolkit/floatwin.hxx> -#include <window.h> -#include <tools/diagnose_ex.h> - -#include <com/sun/star/accessibility/XAccessibleContext.hpp> -#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> - -#if QT5_USING_X11 -#define XK_MISCELLANY -#include <X11/keysymdef.h> -#endif - -using namespace com::sun::star; - -void QtWidget::paintEvent(QPaintEvent* pEvent) -{ - QPainter p(this); - if (!m_rFrame.m_bNullRegion) - p.setClipRegion(m_rFrame.m_aRegion); - - QImage aImage; - if (m_rFrame.m_bUseCairo) - { - cairo_surface_t* pSurface = m_rFrame.m_pSurface.get(); - cairo_surface_flush(pSurface); - - aImage = QImage(cairo_image_surface_get_data(pSurface), - cairo_image_surface_get_width(pSurface), - cairo_image_surface_get_height(pSurface), Qt_DefaultFormat32); - } - else - aImage = *m_rFrame.m_pQImage; - - const qreal fRatio = m_rFrame.devicePixelRatioF(); - aImage.setDevicePixelRatio(fRatio); - QRectF source(pEvent->rect().topLeft() * fRatio, pEvent->rect().size() * fRatio); - p.drawImage(pEvent->rect(), aImage, source); -} - -void QtWidget::resizeEvent(QResizeEvent* pEvent) -{ - const qreal fRatio = m_rFrame.devicePixelRatioF(); - const int nWidth = ceil(pEvent->size().width() * fRatio); - const int nHeight = ceil(pEvent->size().height() * fRatio); - - m_rFrame.maGeometry.nWidth = nWidth; - m_rFrame.maGeometry.nHeight = nHeight; - - if (m_rFrame.m_bUseCairo) - { - if (m_rFrame.m_pSvpGraphics) - { - cairo_surface_t* pSurface - = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight); - cairo_surface_set_user_data(pSurface, SvpSalGraphics::getDamageKey(), - &m_rFrame.m_aDamageHandler, nullptr); - m_rFrame.m_pSvpGraphics->setSurface(pSurface, basegfx::B2IVector(nWidth, nHeight)); - UniqueCairoSurface old_surface(m_rFrame.m_pSurface.release()); - m_rFrame.m_pSurface.reset(pSurface); - - int min_width = qMin(cairo_image_surface_get_width(old_surface.get()), nWidth); - int min_height = qMin(cairo_image_surface_get_height(old_surface.get()), nHeight); - - SalTwoRect rect(0, 0, min_width, min_height, 0, 0, min_width, min_height); - - m_rFrame.m_pSvpGraphics->copySource(rect, old_surface.get()); - } - } - else - { - QImage* pImage = nullptr; - - if (m_rFrame.m_pQImage) - pImage = new QImage(m_rFrame.m_pQImage->copy(0, 0, nWidth, nHeight)); - else - { - pImage = new QImage(nWidth, nHeight, Qt_DefaultFormat32); - pImage->fill(Qt::transparent); - } - - m_rFrame.m_pQtGraphics->ChangeQImage(pImage); - m_rFrame.m_pQImage.reset(pImage); - } - - m_rFrame.CallCallback(SalEvent::Resize, nullptr); -} - -void QtWidget::fillSalAbstractMouseEvent(const QtFrame& rFrame, const QInputEvent* pQEvent, - const QPoint& rPos, Qt::MouseButtons eButtons, int nWidth, - SalAbstractMouseEvent& aSalEvent) -{ - const qreal fRatio = rFrame.devicePixelRatioF(); - const Point aPos = toPoint(rPos * fRatio); - - aSalEvent.mnX = QGuiApplication::isLeftToRight() ? aPos.X() : round(nWidth * fRatio) - aPos.X(); - aSalEvent.mnY = aPos.Y(); - aSalEvent.mnTime = pQEvent->timestamp(); - aSalEvent.mnCode = GetKeyModCode(pQEvent->modifiers()) | GetMouseModCode(eButtons); -} - -#define FILL_SAME(rFrame, nWidth) \ - fillSalAbstractMouseEvent(rFrame, pEvent, pEvent->pos(), pEvent->buttons(), nWidth, aEvent) - -void QtWidget::handleMouseButtonEvent(const QtFrame& rFrame, const QMouseEvent* pEvent, - const ButtonKeyState eState) -{ - SalMouseEvent aEvent; - FILL_SAME(rFrame, rFrame.GetQWidget()->width()); - - switch (pEvent->button()) - { - case Qt::LeftButton: - aEvent.mnButton = MOUSE_LEFT; - break; - case Qt::MiddleButton: - aEvent.mnButton = MOUSE_MIDDLE; - break; - case Qt::RightButton: - aEvent.mnButton = MOUSE_RIGHT; - break; - default: - return; - } - - SalEvent nEventType; - if (eState == ButtonKeyState::Pressed) - nEventType = SalEvent::MouseButtonDown; - else - nEventType = SalEvent::MouseButtonUp; - rFrame.CallCallback(nEventType, &aEvent); -} - -void QtWidget::mousePressEvent(QMouseEvent* pEvent) -{ - handleMousePressEvent(m_rFrame, pEvent); - if (m_rFrame.isPopup() - && !geometry().translated(geometry().topLeft() * -1).contains(pEvent->pos())) - closePopup(); -} - -void QtWidget::mouseReleaseEvent(QMouseEvent* pEvent) { handleMouseReleaseEvent(m_rFrame, pEvent); } - -void QtWidget::mouseMoveEvent(QMouseEvent* pEvent) -{ - SalMouseEvent aEvent; - FILL_SAME(m_rFrame, width()); - - aEvent.mnButton = 0; - - m_rFrame.CallCallback(SalEvent::MouseMove, &aEvent); - pEvent->accept(); -} - -void QtWidget::wheelEvent(QWheelEvent* pEvent) -{ - SalWheelMouseEvent aEvent; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) - fillSalAbstractMouseEvent(m_rFrame, pEvent, pEvent->position().toPoint(), pEvent->buttons(), - width(), aEvent); -#else - fillSalAbstractMouseEvent(m_rFrame, pEvent, pEvent->pos(), pEvent->buttons(), width(), aEvent); -#endif - - // mouse wheel ticks are 120, which we map to 3 lines. - // we have to accumulate for touch scroll to keep track of the absolute delta. - - int nDelta = pEvent->angleDelta().y(), lines; - aEvent.mbHorz = nDelta == 0; - if (aEvent.mbHorz) - { - nDelta = (QGuiApplication::isLeftToRight() ? 1 : -1) * pEvent->angleDelta().x(); - if (!nDelta) - return; - - m_nDeltaX += nDelta; - lines = m_nDeltaX / 40; - m_nDeltaX = m_nDeltaX % 40; - } - else - { - m_nDeltaY += nDelta; - lines = m_nDeltaY / 40; - m_nDeltaY = m_nDeltaY % 40; - } - - aEvent.mnDelta = nDelta; - aEvent.mnNotchDelta = nDelta < 0 ? -1 : 1; - aEvent.mnScrollLines = std::abs(lines); - - m_rFrame.CallCallback(SalEvent::WheelMouse, &aEvent); - pEvent->accept(); -} - -void QtWidget::dragEnterEvent(QDragEnterEvent* event) -{ - if (dynamic_cast<const QtMimeData*>(event->mimeData())) - event->accept(); - else - event->acceptProposedAction(); -} - -// also called when a drop is rejected -void QtWidget::dragLeaveEvent(QDragLeaveEvent*) { m_rFrame.handleDragLeave(); } - -void QtWidget::dragMoveEvent(QDragMoveEvent* pEvent) { m_rFrame.handleDragMove(pEvent); } - -void QtWidget::dropEvent(QDropEvent* pEvent) { m_rFrame.handleDrop(pEvent); } - -void QtWidget::moveEvent(QMoveEvent* pEvent) -{ - if (m_rFrame.m_pTopLevel) - return; - - const Point aPos = toPoint(pEvent->pos() * m_rFrame.devicePixelRatioF()); - m_rFrame.maGeometry.nX = aPos.X(); - m_rFrame.maGeometry.nY = aPos.Y(); - m_rFrame.CallCallback(SalEvent::Move, nullptr); -} - -void QtWidget::showEvent(QShowEvent*) -{ - QSize aSize(m_rFrame.GetQWidget()->size() * m_rFrame.devicePixelRatioF()); - // forcing an immediate update somehow interferes with the hide + show - // sequence from QtFrame::SetModal, if the frame was already set visible, - // resulting in a hidden / unmapped window - SalPaintEvent aPaintEvt(0, 0, aSize.width(), aSize.height()); - m_rFrame.CallCallback(SalEvent::Paint, &aPaintEvt); -} - -void QtWidget::closeEvent(QCloseEvent* /*pEvent*/) -{ - m_rFrame.CallCallback(SalEvent::Close, nullptr); -} - -static sal_uInt16 GetKeyCode(int keyval, Qt::KeyboardModifiers modifiers) -{ - sal_uInt16 nCode = 0; - if (keyval >= Qt::Key_0 && keyval <= Qt::Key_9) - nCode = KEY_0 + (keyval - Qt::Key_0); - else if (keyval >= Qt::Key_A && keyval <= Qt::Key_Z) - nCode = KEY_A + (keyval - Qt::Key_A); - else if (keyval >= Qt::Key_F1 && keyval <= Qt::Key_F26) - nCode = KEY_F1 + (keyval - Qt::Key_F1); - else if (modifiers.testFlag(Qt::KeypadModifier) - && (keyval == Qt::Key_Period || keyval == Qt::Key_Comma)) - // Qt doesn't use a special keyval for decimal separator ("," or ".") - // on numerical keypad, but sets Qt::KeypadModifier in addition - nCode = KEY_DECIMAL; - else - { - switch (keyval) - { - case Qt::Key_Down: - nCode = KEY_DOWN; - break; - case Qt::Key_Up: - nCode = KEY_UP; - break; - case Qt::Key_Left: - nCode = KEY_LEFT; - break; - case Qt::Key_Right: - nCode = KEY_RIGHT; - break; - case Qt::Key_Home: - nCode = KEY_HOME; - break; - case Qt::Key_End: - nCode = KEY_END; - break; - case Qt::Key_PageUp: - nCode = KEY_PAGEUP; - break; - case Qt::Key_PageDown: - nCode = KEY_PAGEDOWN; - break; - case Qt::Key_Return: - case Qt::Key_Enter: - nCode = KEY_RETURN; - break; - case Qt::Key_Escape: - nCode = KEY_ESCAPE; - break; - case Qt::Key_Tab: - // oddly enough, Qt doesn't send Shift-Tab event as 'Tab key pressed with Shift - // modifier' but as 'Backtab key pressed' (while its modifier bits are still - // set to Shift) -- so let's map both Key_Tab and Key_Backtab to VCL's KEY_TAB - case Qt::Key_Backtab: - nCode = KEY_TAB; - break; - case Qt::Key_Backspace: - nCode = KEY_BACKSPACE; - break; - case Qt::Key_Space: - nCode = KEY_SPACE; - break; - case Qt::Key_Insert: - nCode = KEY_INSERT; - break; - case Qt::Key_Delete: - nCode = KEY_DELETE; - break; - case Qt::Key_Plus: - nCode = KEY_ADD; - break; - case Qt::Key_Minus: - nCode = KEY_SUBTRACT; - break; - case Qt::Key_Asterisk: - nCode = KEY_MULTIPLY; - break; - case Qt::Key_Slash: - nCode = KEY_DIVIDE; - break; - case Qt::Key_Period: - nCode = KEY_POINT; - break; - case Qt::Key_Comma: - nCode = KEY_COMMA; - break; - case Qt::Key_Less: - nCode = KEY_LESS; - break; - case Qt::Key_Greater: - nCode = KEY_GREATER; - break; - case Qt::Key_Equal: - nCode = KEY_EQUAL; - break; - case Qt::Key_Find: - nCode = KEY_FIND; - break; - case Qt::Key_Menu: - nCode = KEY_CONTEXTMENU; - break; - case Qt::Key_Help: - nCode = KEY_HELP; - break; - case Qt::Key_Undo: - nCode = KEY_UNDO; - break; - case Qt::Key_Redo: - nCode = KEY_REPEAT; - break; - case Qt::Key_Cancel: - nCode = KEY_F11; - break; - case Qt::Key_AsciiTilde: - nCode = KEY_TILDE; - break; - case Qt::Key_QuoteLeft: - nCode = KEY_QUOTELEFT; - break; - case Qt::Key_BracketLeft: - nCode = KEY_BRACKETLEFT; - break; - case Qt::Key_BracketRight: - nCode = KEY_BRACKETRIGHT; - break; - case Qt::Key_Semicolon: - nCode = KEY_SEMICOLON; - break; - case Qt::Key_Copy: - nCode = KEY_COPY; - break; - case Qt::Key_Cut: - nCode = KEY_CUT; - break; - case Qt::Key_Open: - nCode = KEY_OPEN; - break; - case Qt::Key_Paste: - nCode = KEY_PASTE; - break; - } - } - - return nCode; -} - -void QtWidget::commitText(QtFrame& rFrame, const QString& aText) -{ - SalExtTextInputEvent aInputEvent; - aInputEvent.mpTextAttr = nullptr; - aInputEvent.mnCursorFlags = 0; - aInputEvent.maText = toOUString(aText); - aInputEvent.mnCursorPos = aInputEvent.maText.getLength(); - - SolarMutexGuard aGuard; - vcl::DeletionListener aDel(&rFrame); - rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent); - if (!aDel.isDeleted()) - rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); -} - -bool QtWidget::handleKeyEvent(QtFrame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent, - const ButtonKeyState eState) -{ - sal_uInt16 nCode = GetKeyCode(pEvent->key(), pEvent->modifiers()); - if (eState == ButtonKeyState::Pressed && nCode == 0 && pEvent->text().length() > 1 - && rWidget.testAttribute(Qt::WA_InputMethodEnabled)) - { - commitText(rFrame, pEvent->text()); - pEvent->accept(); - return true; - } - - if (nCode == 0 && pEvent->text().isEmpty()) - { - sal_uInt16 nModCode = GetKeyModCode(pEvent->modifiers()); - SalKeyModEvent aModEvt; - aModEvt.mbDown = eState == ButtonKeyState::Pressed; - aModEvt.mnModKeyCode = ModKeyFlags::NONE; - -#if QT5_USING_X11 - if (QGuiApplication::platformName() == "xcb") - { - // pressing just the ctrl key leads to a keysym of XK_Control but - // the event state does not contain ControlMask. In the release - // event it's the other way round: it does contain the Control mask. - // The modifier mode therefore has to be adapted manually. - ModKeyFlags nExtModMask = ModKeyFlags::NONE; - sal_uInt16 nModMask = 0; - switch (pEvent->nativeVirtualKey()) - { - case XK_Control_L: - nExtModMask = ModKeyFlags::LeftMod1; - nModMask = KEY_MOD1; - break; - case XK_Control_R: - nExtModMask = ModKeyFlags::RightMod1; - nModMask = KEY_MOD1; - break; - case XK_Alt_L: - nExtModMask = ModKeyFlags::LeftMod2; - nModMask = KEY_MOD2; - break; - case XK_Alt_R: - nExtModMask = ModKeyFlags::RightMod2; - nModMask = KEY_MOD2; - break; - case XK_Shift_L: - nExtModMask = ModKeyFlags::LeftShift; - nModMask = KEY_SHIFT; - break; - case XK_Shift_R: - nExtModMask = ModKeyFlags::RightShift; - nModMask = KEY_SHIFT; - break; - // Map Meta/Super keys to MOD3 modifier on all Unix systems - // except macOS - case XK_Meta_L: - case XK_Super_L: - nExtModMask = ModKeyFlags::LeftMod3; - nModMask = KEY_MOD3; - break; - case XK_Meta_R: - case XK_Super_R: - nExtModMask = ModKeyFlags::RightMod3; - nModMask = KEY_MOD3; - break; - } - - if (eState == ButtonKeyState::Released) - { - // sending the old mnModKeyCode mask on release is needed to - // implement the writing direction switch with Ctrl + L/R-Shift - aModEvt.mnModKeyCode = rFrame.m_nKeyModifiers; - nModCode &= ~nModMask; - rFrame.m_nKeyModifiers &= ~nExtModMask; - } - else - { - nModCode |= nModMask; - rFrame.m_nKeyModifiers |= nExtModMask; - aModEvt.mnModKeyCode = rFrame.m_nKeyModifiers; - } - } -#endif - aModEvt.mnCode = nModCode; - - rFrame.CallCallback(SalEvent::KeyModChange, &aModEvt); - return false; - } - - // prevent interference of writing direction switch (Ctrl + L/R-Shift) with "normal" shortcuts - rFrame.m_nKeyModifiers = ModKeyFlags::NONE; - - SalKeyEvent aEvent; - aEvent.mnCharCode = (pEvent->text().isEmpty() ? 0 : pEvent->text().at(0).unicode()); - aEvent.mnRepeat = 0; - aEvent.mnCode = nCode; - aEvent.mnCode |= GetKeyModCode(pEvent->modifiers()); - - QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle); - - bool bStopProcessingKey; - if (eState == ButtonKeyState::Pressed) - bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyInput, &aEvent); - else - bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyUp, &aEvent); - if (bStopProcessingKey) - pEvent->accept(); - return bStopProcessingKey; -} - -bool QtWidget::handleEvent(QtFrame& rFrame, const QWidget& rWidget, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::ShortcutOverride) - { - // ignore non-spontaneous QEvent::ShortcutOverride events, - // since such an extra event is sent e.g. with Orca screen reader enabled, - // so that two events of that kind (the "real one" and a non-spontaneous one) - // would otherwise be processed, resulting in duplicate input as 'handleKeyEvent' - // is called below (s. tdf#122053) - if (!pEvent->spontaneous()) - { - return false; - } - - // Accepted event disables shortcut activation, - // but enables keypress event. - // If event is not accepted and shortcut is successfully activated, - // KeyPress event is omitted. - // - // Instead of processing keyPressEvent, handle ShortcutOverride event, - // and if it's handled - disable the shortcut, it should have been activated. - // Don't process keyPressEvent generated after disabling shortcut since it was handled here. - // If event is not handled, don't accept it and let Qt activate related shortcut. - if (handleKeyEvent(rFrame, rWidget, static_cast<QKeyEvent*>(pEvent), - ButtonKeyState::Pressed)) - return true; - } - return false; -} - -bool QtWidget::event(QEvent* pEvent) -{ - return handleEvent(m_rFrame, *this, pEvent) || QWidget::event(pEvent); -} - -void QtWidget::keyReleaseEvent(QKeyEvent* pEvent) -{ - if (!handleKeyReleaseEvent(m_rFrame, *this, pEvent)) - QWidget::keyReleaseEvent(pEvent); -} - -void QtWidget::focusInEvent(QFocusEvent*) { m_rFrame.CallCallback(SalEvent::GetFocus, nullptr); } - -void QtWidget::closePopup() -{ - VclPtr<FloatingWindow> pFirstFloat = ImplGetSVData()->mpWinData->mpFirstFloat; - if (pFirstFloat && !(pFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose)) - { - SolarMutexGuard aGuard; - pFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll); - } -} - -void QtWidget::focusOutEvent(QFocusEvent*) -{ - m_rFrame.m_nKeyModifiers = ModKeyFlags::NONE; - endExtTextInput(); - m_rFrame.CallCallback(SalEvent::LoseFocus, nullptr); - closePopup(); -} - -QtWidget::QtWidget(QtFrame& rFrame, Qt::WindowFlags f) - : QWidget(Q_NULLPTR, f) - , m_rFrame(rFrame) - , m_bNonEmptyIMPreeditSeen(false) - , m_nDeltaX(0) - , m_nDeltaY(0) -{ - create(); - setMouseTracking(true); - setFocusPolicy(Qt::StrongFocus); -} - -static ExtTextInputAttr lcl_MapUndrelineStyle(QTextCharFormat::UnderlineStyle us) -{ - switch (us) - { - case QTextCharFormat::NoUnderline: - return ExtTextInputAttr::NONE; - case QTextCharFormat::DotLine: - return ExtTextInputAttr::DottedUnderline; - case QTextCharFormat::DashDotDotLine: - case QTextCharFormat::DashDotLine: - return ExtTextInputAttr::DashDotUnderline; - case QTextCharFormat::WaveUnderline: - return ExtTextInputAttr::GrayWaveline; - default: - return ExtTextInputAttr::Underline; - } -} - -void QtWidget::inputMethodEvent(QInputMethodEvent* pEvent) -{ - if (!pEvent->commitString().isEmpty()) - commitText(m_rFrame, pEvent->commitString()); - else - { - SalExtTextInputEvent aInputEvent; - aInputEvent.mpTextAttr = nullptr; - aInputEvent.mnCursorFlags = 0; - aInputEvent.maText = toOUString(pEvent->preeditString()); - aInputEvent.mnCursorPos = 0; - - const sal_Int32 nLength = aInputEvent.maText.getLength(); - const QList<QInputMethodEvent::Attribute>& rAttrList = pEvent->attributes(); - std::vector<ExtTextInputAttr> aTextAttrs(std::max(sal_Int32(1), nLength), - ExtTextInputAttr::NONE); - aInputEvent.mpTextAttr = aTextAttrs.data(); - - for (int i = 0; i < rAttrList.size(); ++i) - { - const QInputMethodEvent::Attribute& rAttr = rAttrList.at(i); - switch (rAttr.type) - { - case QInputMethodEvent::TextFormat: - { - QTextCharFormat aCharFormat - = qvariant_cast<QTextFormat>(rAttr.value).toCharFormat(); - if (aCharFormat.isValid()) - { - ExtTextInputAttr aETIP - = lcl_MapUndrelineStyle(aCharFormat.underlineStyle()); - if (aCharFormat.hasProperty(QTextFormat::BackgroundBrush)) - aETIP |= ExtTextInputAttr::Highlight; - if (aCharFormat.fontStrikeOut()) - aETIP |= ExtTextInputAttr::RedText; - for (int j = rAttr.start; j < rAttr.start + rAttr.length; j++) - aTextAttrs[j] = aETIP; - } - break; - } - case QInputMethodEvent::Cursor: - { - aInputEvent.mnCursorPos = rAttr.start; - if (rAttr.length == 0) - aInputEvent.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE; - break; - } - default: - SAL_WARN("vcl.qt5", "Unhandled QInputMethodEvent attribute: " - << static_cast<int>(rAttr.type)); - break; - } - } - - const bool bIsEmpty = aInputEvent.maText.isEmpty(); - if (m_bNonEmptyIMPreeditSeen || !bIsEmpty) - { - SolarMutexGuard aGuard; - vcl::DeletionListener aDel(&m_rFrame); - m_rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent); - if (!aDel.isDeleted() && bIsEmpty) - m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); - m_bNonEmptyIMPreeditSeen = !bIsEmpty; - } - } - - pEvent->accept(); -} - -static bool lcl_retrieveSurrounding(sal_Int32& rPosition, sal_Int32& rAnchor, QString* pText, - QString* pSelection) -{ - SolarMutexGuard aGuard; - vcl::Window* pFocusWin = Application::GetFocusWindow(); - if (!pFocusWin) - return false; - - uno::Reference<accessibility::XAccessibleEditableText> xText; - try - { - uno::Reference<accessibility::XAccessible> xAccessible(pFocusWin->GetAccessible()); - if (xAccessible.is()) - xText = FindFocusedEditableText(xAccessible->getAccessibleContext()); - } - catch (const uno::Exception&) - { - TOOLS_WARN_EXCEPTION("vcl.qt5", "Exception in getting input method surrounding text"); - } - - if (xText.is()) - { - rPosition = xText->getCaretPosition(); - if (rPosition != -1) - { - if (pText) - *pText = toQString(xText->getText()); - - sal_Int32 nSelStart = xText->getSelectionStart(); - sal_Int32 nSelEnd = xText->getSelectionEnd(); - if (nSelStart == nSelEnd) - { - rAnchor = rPosition; - } - else - { - if (rPosition == nSelStart) - rAnchor = nSelEnd; - else - rAnchor = nSelStart; - if (pSelection) - *pSelection = toQString(xText->getSelectedText()); - } - return true; - } - } - - return false; -} - -QVariant QtWidget::inputMethodQuery(Qt::InputMethodQuery property) const -{ - switch (property) - { - case Qt::ImSurroundingText: - { - QString aText; - sal_Int32 nCursorPos, nAnchor; - if (lcl_retrieveSurrounding(nCursorPos, nAnchor, &aText, nullptr)) - return QVariant(aText); - return QVariant(); - } - case Qt::ImCursorPosition: - { - sal_Int32 nCursorPos, nAnchor; - if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr)) - return QVariant(static_cast<int>(nCursorPos)); - return QVariant(); - } - case Qt::ImCursorRectangle: - { - const qreal fRatio = m_rFrame.devicePixelRatioF(); - SalExtTextInputPosEvent aPosEvent; - m_rFrame.CallCallback(SalEvent::ExtTextInputPos, &aPosEvent); - return QVariant(QRect(aPosEvent.mnX / fRatio, aPosEvent.mnY / fRatio, - aPosEvent.mnWidth / fRatio, aPosEvent.mnHeight / fRatio)); - } - case Qt::ImAnchorPosition: - { - sal_Int32 nCursorPos, nAnchor; - if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr)) - return QVariant(static_cast<int>(nAnchor)); - return QVariant(); - } - case Qt::ImCurrentSelection: - { - QString aSelection; - sal_Int32 nCursorPos, nAnchor; - if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, &aSelection)) - return QVariant(aSelection); - return QVariant(); - } - default: - return QWidget::inputMethodQuery(property); - } -} - -void QtWidget::endExtTextInput() -{ - if (m_bNonEmptyIMPreeditSeen) - { - m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); - m_bNonEmptyIMPreeditSeen = false; - } -} - -void QtWidget::changeEvent(QEvent* pEvent) -{ - switch (pEvent->type()) - { - case QEvent::FontChange: - [[fallthrough]]; - case QEvent::PaletteChange: - [[fallthrough]]; - case QEvent::StyleChange: - { - auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); - assert(pSalInst); - pSalInst->UpdateStyle(QEvent::FontChange == pEvent->type()); - break; - } - default: - break; - } - QWidget::changeEvent(pEvent); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5XAccessible.cxx b/vcl/qt5/Qt5XAccessible.cxx deleted file mode 100644 index 8bb4f837d6d9..000000000000 --- a/vcl/qt5/Qt5XAccessible.cxx +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.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 <Qt5XAccessible.hxx> -#include <Qt5XAccessible.moc> - -#include <Qt5Frame.hxx> -#include <Qt5Tools.hxx> -#include <Qt5Widget.hxx> - -#include <com/sun/star/accessibility/XAccessible.hpp> - -#include <sal/log.hxx> - -using namespace css::accessibility; -using namespace css::uno; - -QtXAccessible::QtXAccessible(Reference<XAccessible> xAccessible) - : m_xAccessible(xAccessible) -{ -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtAccessibleEventListener.cxx b/vcl/qt5/QtAccessibleEventListener.cxx new file mode 100644 index 000000000000..fa8c540024c4 --- /dev/null +++ b/vcl/qt5/QtAccessibleEventListener.cxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtAccessibleEventListener.hxx> + +#include <sal/log.hxx> + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> + +#include <QtGui/QAccessible> + +using namespace css; +using namespace css::accessibility; +using namespace css::lang; +using namespace css::uno; + +QtAccessibleEventListener::QtAccessibleEventListener(const Reference<XAccessible> xAccessible, + QtAccessibleWidget* pAccessibleWidget) + : m_xAccessible(xAccessible) + , m_pAccessibleWidget(pAccessibleWidget) +{ +} + +void QtAccessibleEventListener::notifyEvent(const css::accessibility::AccessibleEventObject& aEvent) +{ + QAccessibleInterface* pQAccessibleInterface = m_pAccessibleWidget; + + Reference<XAccessible> xChild; + switch (aEvent.EventId) + { + case AccessibleEventId::NAME_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::NameChanged)); + return; + case AccessibleEventId::DESCRIPTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::DescriptionChanged)); + return; + case AccessibleEventId::ACTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActionChanged)); + return; + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActiveDescendantChanged)); + return; + case AccessibleEventId::CHILD: + { + QAccessible::Event event = QAccessible::InvalidEvent; + if (aEvent.OldValue >>= xChild) + event = QAccessible::ObjectDestroyed; + if (aEvent.NewValue >>= xChild) + event = QAccessible::ObjectCreated; + if (event != QAccessible::InvalidEvent) + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, event)); + return; + } + case AccessibleEventId::SELECTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection)); + return; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::VisibleDataChanged)); + return; + case AccessibleEventId::TEXT_SELECTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection)); + return; + case AccessibleEventId::TEXT_ATTRIBUTE_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::AttributeChanged)); + return; + case AccessibleEventId::TABLE_CAPTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableCaptionChanged)); + return; + case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: + QAccessible::updateAccessibility(new QAccessibleEvent( + pQAccessibleInterface, QAccessible::TableColumnDescriptionChanged)); + return; + case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableColumnHeaderChanged)); + return; + case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: + QAccessible::updateAccessibility(new QAccessibleEvent( + pQAccessibleInterface, QAccessible::TableRowDescriptionChanged)); + return; + case AccessibleEventId::TABLE_ROW_HEADER_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableRowHeaderChanged)); + return; + case AccessibleEventId::TABLE_SUMMARY_CHANGED: + case AccessibleEventId::CARET_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableSummaryChanged)); + return; + case AccessibleEventId::SELECTION_CHANGED_ADD: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionAdd)); + return; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionRemove)); + return; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionWithin)); + return; + case AccessibleEventId::PAGE_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::PageChanged)); + return; + case AccessibleEventId::SECTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SectionChanged)); + return; + case AccessibleEventId::TEXT_CHANGED: + case AccessibleEventId::COLUMN_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TextColumnChanged)); + return; + case AccessibleEventId::BOUNDRECT_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::LocationChanged)); + return; + case AccessibleEventId::STATE_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::ForegroundChanged)); + return; + case AccessibleEventId::ROLE_CHANGED: + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + case AccessibleEventId::VALUE_CHANGED: + case AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED: + case AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED: + case AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED: + case AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED: + case AccessibleEventId::LABEL_FOR_RELATION_CHANGED: + case AccessibleEventId::LABELED_BY_RELATION_CHANGED: + case AccessibleEventId::MEMBER_OF_RELATION_CHANGED: + case AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED: + case AccessibleEventId::HYPERTEXT_CHANGED: + case AccessibleEventId::TABLE_MODEL_CHANGED: + case AccessibleEventId::LISTBOX_ENTRY_EXPANDED: + case AccessibleEventId::LISTBOX_ENTRY_COLLAPSED: + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS: + default: + SAL_WARN("vcl.qt5", "Unmapped AccessibleEventId: " << aEvent.EventId); + return; + } +} + +void QtAccessibleEventListener::disposing(const EventObject& /* Source */) {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx new file mode 100644 index 000000000000..9f5b6ced8808 --- /dev/null +++ b/vcl/qt5/QtAccessibleWidget.cxx @@ -0,0 +1,1476 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtAccessibleWidget.hxx> +#include <QtAccessibleWidget.moc> + +#include <QtGui/QAccessibleInterface> + +#include <QtAccessibleEventListener.hxx> +#include <QtFrame.hxx> +#include <QtTools.hxx> +#include <QtWidget.hxx> +#include <QtXAccessible.hxx> + +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleScrollType.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleAction.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp> +#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> +#include <com/sun/star/accessibility/XAccessibleTable.hpp> +#include <com/sun/star/accessibility/XAccessibleTableSelection.hpp> +#include <com/sun/star/accessibility/XAccessibleText.hpp> +#include <com/sun/star/accessibility/XAccessibleValue.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/uno/Sequence.hxx> + +#include <comphelper/AccessibleImplementationHelper.hxx> +#include <o3tl/any.hxx> +#include <sal/log.hxx> + +using namespace css; +using namespace css::accessibility; +using namespace css::beans; +using namespace css::uno; + +QtAccessibleWidget::QtAccessibleWidget(const Reference<XAccessible> xAccessible, QObject* pObject) + : m_xAccessible(xAccessible) + , m_pObject(pObject) +{ + Reference<XAccessibleContext> xContext = xAccessible->getAccessibleContext(); + Reference<XAccessibleEventBroadcaster> xBroadcaster(xContext, UNO_QUERY); + if (xBroadcaster.is()) + { + Reference<XAccessibleEventListener> xListener( + new QtAccessibleEventListener(xAccessible, this)); + xBroadcaster->addAccessibleEventListener(xListener); + } +} + +Reference<XAccessibleContext> QtAccessibleWidget::getAccessibleContextImpl() const +{ + Reference<XAccessibleContext> xAc; + + if (m_xAccessible.is()) + { + try + { + xAc = m_xAccessible->getAccessibleContext(); + } + catch (css::lang::DisposedException /*ex*/) + { + SAL_WARN("vcl.qt5", "Accessible context disposed already"); + } + // sometimes getAccessibleContext throws also RuntimeException if context is no longer alive + catch (css::uno::RuntimeException /*ex*/) + { + // so let's catch it here, cuz otherwise soffice falls flat on its face + // with FatalError and nothing else + SAL_WARN("vcl.qt5", "Accessible context no longer alive"); + } + } + + return xAc; +} + +css::uno::Reference<css::accessibility::XAccessibleTable> +QtAccessibleWidget::getAccessibleTableForParent() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return nullptr; + + Reference<XAccessible> xParent = xAcc->getAccessibleParent(); + if (!xParent.is()) + return nullptr; + + Reference<XAccessibleContext> xParentContext = xParent->getAccessibleContext(); + if (!xParentContext.is()) + return nullptr; + + return Reference<XAccessibleTable>(xParentContext, UNO_QUERY); +} + +QWindow* QtAccessibleWidget::window() const { return nullptr; } + +int QtAccessibleWidget::childCount() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + return xAc->getAccessibleChildCount(); +} + +int QtAccessibleWidget::indexOfChild(const QAccessibleInterface* /* child */) const { return 0; } + +namespace +{ +sal_Int16 lcl_matchQtTextBoundaryType(QAccessible::TextBoundaryType boundaryType) +{ + switch (boundaryType) + { + case QAccessible::CharBoundary: + return com::sun::star::accessibility::AccessibleTextType::CHARACTER; + case QAccessible::WordBoundary: + return com::sun::star::accessibility::AccessibleTextType::WORD; + case QAccessible::SentenceBoundary: + return com::sun::star::accessibility::AccessibleTextType::SENTENCE; + case QAccessible::ParagraphBoundary: + return com::sun::star::accessibility::AccessibleTextType::PARAGRAPH; + case QAccessible::LineBoundary: + return com::sun::star::accessibility::AccessibleTextType::LINE; + case QAccessible::NoBoundary: + // assert here, better handle it directly at call site + assert(false + && "No match for QAccessible::NoBoundary, handle it separately at call site."); + break; + default: + break; + } + + SAL_WARN("vcl.qt5", "Unmatched text boundary type: " << boundaryType); + return -1; +} + +QAccessible::Relation lcl_matchUnoRelation(short relationType) +{ + switch (relationType) + { + case AccessibleRelationType::CONTROLLER_FOR: + return QAccessible::Controller; + case AccessibleRelationType::CONTROLLED_BY: + return QAccessible::Controlled; + case AccessibleRelationType::LABEL_FOR: + return QAccessible::Label; + case AccessibleRelationType::LABELED_BY: + return QAccessible::Labelled; + case AccessibleRelationType::INVALID: + case AccessibleRelationType::CONTENT_FLOWS_FROM: + case AccessibleRelationType::CONTENT_FLOWS_TO: + case AccessibleRelationType::MEMBER_OF: + case AccessibleRelationType::SUB_WINDOW_OF: + case AccessibleRelationType::NODE_CHILD_OF: + case AccessibleRelationType::DESCRIBED_BY: + default: + SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType); + return {}; + } +} + +short lcl_matchQtRelation(QAccessible::Relation relationType) +{ + switch (relationType) + { + case QAccessible::Controller: + return AccessibleRelationType::CONTROLLER_FOR; + case QAccessible::Controlled: + return AccessibleRelationType::CONTROLLED_BY; + case QAccessible::Label: + return AccessibleRelationType::LABEL_FOR; + case QAccessible::Labelled: + return AccessibleRelationType::LABELED_BY; + default: + SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType); + } + return 0; +} + +void lcl_appendRelation(QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>* relations, + AccessibleRelation aRelation) +{ + QAccessible::Relation aQRelation = lcl_matchUnoRelation(aRelation.RelationType); + sal_uInt32 nTargetCount = aRelation.TargetSet.getLength(); + + for (sal_uInt32 i = 0; i < nTargetCount; i++) + { + Reference<XAccessible> xAccessible(aRelation.TargetSet[i], uno::UNO_QUERY); + relations->append( + { QAccessible::queryAccessibleInterface(new QtXAccessible(xAccessible)), aQRelation }); + } +} +} + +QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> +QtAccessibleWidget::relations(QAccessible::Relation match) const +{ + QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> relations; + + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return relations; + + Reference<XAccessibleRelationSet> xRelationSet = xAc->getAccessibleRelationSet(); + if (xRelationSet.is()) + { + if (match == QAccessible::AllRelations) + { + int count = xRelationSet->getRelationCount(); + for (int i = 0; i < count; i++) + { + AccessibleRelation aRelation = xRelationSet->getRelation(i); + lcl_appendRelation(&relations, aRelation); + } + } + else + { + AccessibleRelation aRelation = xRelationSet->getRelation(lcl_matchQtRelation(match)); + lcl_appendRelation(&relations, aRelation); + } + } + + return relations; +} + +QAccessibleInterface* QtAccessibleWidget::focusChild() const +{ + /* if (m_pWindow->HasChildPathFocus()) + return QAccessible::queryAccessibleInterface( + new QtXAccessible(m_xAccessible->getAccessibleContext()->getAccessibleChild(index))); */ + return QAccessible::queryAccessibleInterface(object()); +} + +QRect QtAccessibleWidget::rect() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QRect(); + + Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); + awt::Point aPoint = xAccessibleComponent->getLocation(); + awt::Size aSize = xAccessibleComponent->getSize(); + + return QRect(aPoint.X, aPoint.Y, aSize.Width, aSize.Height); +} + +QAccessibleInterface* QtAccessibleWidget::parent() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + return QAccessible::queryAccessibleInterface(new QtXAccessible(xAc->getAccessibleParent())); +} +QAccessibleInterface* QtAccessibleWidget::child(int index) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + return QAccessible::queryAccessibleInterface(new QtXAccessible(xAc->getAccessibleChild(index))); +} + +QString QtAccessibleWidget::text(QAccessible::Text text) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QString(); + + switch (text) + { + case QAccessible::Name: + return toQString(xAc->getAccessibleName()); + case QAccessible::Description: + case QAccessible::DebugDescription: + return toQString(xAc->getAccessibleDescription()); + case QAccessible::Value: + case QAccessible::Help: + case QAccessible::Accelerator: + case QAccessible::UserText: + default: + return QString("Unknown"); + } +} +QAccessible::Role QtAccessibleWidget::role() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QAccessible::NoRole; + + switch (xAc->getAccessibleRole()) + { + case AccessibleRole::UNKNOWN: + return QAccessible::NoRole; + + case AccessibleRole::ALERT: + return QAccessible::AlertMessage; + + case AccessibleRole::COLUMN_HEADER: + return QAccessible::ColumnHeader; + + case AccessibleRole::CANVAS: + return QAccessible::Canvas; + + case AccessibleRole::CHECK_BOX: + return QAccessible::CheckBox; + + case AccessibleRole::CHECK_MENU_ITEM: + return QAccessible::MenuItem; + + case AccessibleRole::COLOR_CHOOSER: + return QAccessible::ColorChooser; + + case AccessibleRole::COMBO_BOX: + return QAccessible::ComboBox; + + case AccessibleRole::DATE_EDITOR: + return QAccessible::EditableText; + + case AccessibleRole::DESKTOP_ICON: + return QAccessible::Graphic; + + case AccessibleRole::DESKTOP_PANE: + case AccessibleRole::DIRECTORY_PANE: + return QAccessible::Pane; + + case AccessibleRole::DIALOG: + return QAccessible::Dialog; + + case AccessibleRole::DOCUMENT: + return QAccessible::Document; + + case AccessibleRole::EMBEDDED_OBJECT: + return QAccessible::UserRole; + + case AccessibleRole::END_NOTE: + return QAccessible::Note; + + case AccessibleRole::FILLER: + return QAccessible::Whitespace; + + case AccessibleRole::FONT_CHOOSER: + return QAccessible::UserRole; + + case AccessibleRole::FOOTER: + return QAccessible::Footer; + + case AccessibleRole::FOOTNOTE: + return QAccessible::Note; + + case AccessibleRole::FRAME: // top-level window with title bar + return QAccessible::Window; + + case AccessibleRole::GLASS_PANE: + return QAccessible::UserRole; + + case AccessibleRole::GRAPHIC: + return QAccessible::Graphic; + + case AccessibleRole::GROUP_BOX: + return QAccessible::Grouping; + + case AccessibleRole::HEADER: + return QAccessible::UserRole; + + case AccessibleRole::HEADING: + return QAccessible::Heading; + + case AccessibleRole::HYPER_LINK: + return QAccessible::Link; + + case AccessibleRole::ICON: + return QAccessible::Graphic; + + case AccessibleRole::INTERNAL_FRAME: + return QAccessible::UserRole; + + case AccessibleRole::LABEL: + return QAccessible::StaticText; + + case AccessibleRole::LAYERED_PANE: + return QAccessible::Pane; + + case AccessibleRole::LIST: + return QAccessible::List; + + case AccessibleRole::LIST_ITEM: + return QAccessible::ListItem; + + case AccessibleRole::MENU: + case AccessibleRole::MENU_BAR: + return QAccessible::MenuBar; + + case AccessibleRole::MENU_ITEM: + return QAccessible::MenuItem; + + case AccessibleRole::OPTION_PANE: + return QAccessible::Pane; + + case AccessibleRole::PAGE_TAB: + return QAccessible::PageTab; + + case AccessibleRole::PAGE_TAB_LIST: + return QAccessible::PageTabList; + + case AccessibleRole::PANEL: + return QAccessible::Pane; + + case AccessibleRole::PARAGRAPH: + return QAccessible::Paragraph; + + case AccessibleRole::PASSWORD_TEXT: + return QAccessible::EditableText; + + case AccessibleRole::POPUP_MENU: + return QAccessible::PopupMenu; + + case AccessibleRole::PUSH_BUTTON: + return QAccessible::Button; + + case AccessibleRole::PROGRESS_BAR: + return QAccessible::ProgressBar; + + case AccessibleRole::RADIO_BUTTON: + return QAccessible::RadioButton; + + case AccessibleRole::RADIO_MENU_ITEM: + return QAccessible::MenuItem; + + case AccessibleRole::ROW_HEADER: + return QAccessible::RowHeader; + + case AccessibleRole::ROOT_PANE: + return QAccessible::Pane; + + case AccessibleRole::SCROLL_BAR: + return QAccessible::ScrollBar; + + case AccessibleRole::SCROLL_PANE: + return QAccessible::Pane; + + case AccessibleRole::SHAPE: + return QAccessible::Graphic; + + case AccessibleRole::SEPARATOR: + return QAccessible::Separator; + + case AccessibleRole::SLIDER: + return QAccessible::Slider; + + case AccessibleRole::SPIN_BOX: + return QAccessible::SpinBox; + + case AccessibleRole::SPLIT_PANE: + return QAccessible::Pane; + + case AccessibleRole::STATUS_BAR: + return QAccessible::StatusBar; + + case AccessibleRole::TABLE: + return QAccessible::Table; + + case AccessibleRole::TABLE_CELL: + return QAccessible::Cell; + + case AccessibleRole::TEXT: + return QAccessible::EditableText; + + case AccessibleRole::TEXT_FRAME: + return QAccessible::UserRole; + + case AccessibleRole::TOGGLE_BUTTON: + return QAccessible::Button; + + case AccessibleRole::TOOL_BAR: + return QAccessible::ToolBar; + + case AccessibleRole::TOOL_TIP: + return QAccessible::ToolTip; + + case AccessibleRole::TREE: + return QAccessible::Tree; + + case AccessibleRole::VIEW_PORT: + return QAccessible::UserRole; + + case AccessibleRole::BUTTON_DROPDOWN: + return QAccessible::Button; + + case AccessibleRole::BUTTON_MENU: + return QAccessible::Button; + + case AccessibleRole::CAPTION: + return QAccessible::StaticText; + + case AccessibleRole::CHART: + return QAccessible::Chart; + + case AccessibleRole::EDIT_BAR: + return QAccessible::Equation; + + case AccessibleRole::FORM: + return QAccessible::Form; + + case AccessibleRole::IMAGE_MAP: + return QAccessible::Graphic; + + case AccessibleRole::NOTE: + return QAccessible::Note; + + case AccessibleRole::RULER: + return QAccessible::UserRole; + + case AccessibleRole::SECTION: + return QAccessible::Section; + + case AccessibleRole::TREE_ITEM: + return QAccessible::TreeItem; + + case AccessibleRole::TREE_TABLE: + return QAccessible::Tree; + + case AccessibleRole::COMMENT: + return QAccessible::Note; + + case AccessibleRole::COMMENT_END: + return QAccessible::UserRole; + + case AccessibleRole::DOCUMENT_PRESENTATION: + return QAccessible::Document; + + case AccessibleRole::DOCUMENT_SPREADSHEET: + return QAccessible::Document; + + case AccessibleRole::DOCUMENT_TEXT: + return QAccessible::Document; + + case AccessibleRole::STATIC: + return QAccessible::StaticText; + + /* Ignore window objects for sub-menus, combo- and list boxes, + * which are exposed as children of their parents. + */ + case AccessibleRole::WINDOW: // top-level window without title bar + { + return QAccessible::Window; + } + } + + SAL_WARN("vcl.qt5", "Unmapped role: " << getAccessibleContextImpl()->getAccessibleRole()); + return QAccessible::NoRole; +} + +namespace +{ +void lcl_addState(QAccessible::State* state, sal_Int16 nState) +{ + switch (nState) + { + case AccessibleStateType::INVALID: + state->invalid = true; + break; + case AccessibleStateType::ACTIVE: + state->active = true; + break; + case AccessibleStateType::ARMED: + // No match + break; + case AccessibleStateType::BUSY: + state->busy = true; + break; + case AccessibleStateType::CHECKED: + state->checked = true; + break; + case AccessibleStateType::EDITABLE: + state->editable = true; + break; + case AccessibleStateType::ENABLED: + state->disabled = false; + break; + case AccessibleStateType::EXPANDABLE: + state->expandable = true; + break; + case AccessibleStateType::EXPANDED: + state->expanded = true; + break; + case AccessibleStateType::FOCUSABLE: + state->focusable = true; + break; + case AccessibleStateType::FOCUSED: + state->focused = true; + break; + case AccessibleStateType::HORIZONTAL: + // No match + break; + case AccessibleStateType::ICONIFIED: + // No match + break; + case AccessibleStateType::INDETERMINATE: + // No match + break; + case AccessibleStateType::MANAGES_DESCENDANTS: + // No match + break; + case AccessibleStateType::MODAL: + state->modal = true; + break; + case AccessibleStateType::MOVEABLE: + state->movable = true; + break; + case AccessibleStateType::MULTI_LINE: + state->multiLine = true; + break; + case AccessibleStateType::OPAQUE: + // No match + break; + case AccessibleStateType::PRESSED: + state->pressed = true; + break; + case AccessibleStateType::RESIZABLE: + state->sizeable = true; + break; + case AccessibleStateType::SELECTABLE: + state->selectable = true; + break; + case AccessibleStateType::SELECTED: + state->selected = true; + break; + case AccessibleStateType::SENSITIVE: + // No match + break; + case AccessibleStateType::SHOWING: + // No match + break; + case AccessibleStateType::SINGLE_LINE: + // No match + break; + case AccessibleStateType::STALE: + // No match + break; + case AccessibleStateType::TRANSIENT: + // No match + break; + case AccessibleStateType::VERTICAL: + // No match + break; + case AccessibleStateType::VISIBLE: + state->invisible = false; + break; + case AccessibleStateType::DEFAULT: + // No match + break; + case AccessibleStateType::DEFUNC: + state->invalid = true; + break; + case AccessibleStateType::MULTI_SELECTABLE: + state->multiSelectable = true; + break; + default: + SAL_WARN("vcl.qt5", "Unmapped state: " << nState); + break; + } +} +} + +QAccessible::State QtAccessibleWidget::state() const +{ + QAccessible::State state; + + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return state; + + Reference<XAccessibleStateSet> xStateSet(xAc->getAccessibleStateSet()); + + if (!xStateSet.is()) + return state; + + Sequence<sal_Int16> aStates = xStateSet->getStates(); + + for (const sal_Int16 nState : aStates) + { + lcl_addState(&state, nState); + } + + return state; +} + +QColor QtAccessibleWidget::foregroundColor() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QColor(); + + Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); + return toQColor(Color(ColorTransparency, xAccessibleComponent->getForeground())); +} + +QColor QtAccessibleWidget::backgroundColor() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QColor(); + + Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); + return toQColor(Color(ColorTransparency, xAccessibleComponent->getBackground())); +} + +void* QtAccessibleWidget::interface_cast(QAccessible::InterfaceType t) +{ + if (t == QAccessible::ActionInterface) + return static_cast<QAccessibleActionInterface*>(this); + if (t == QAccessible::TextInterface) + return static_cast<QAccessibleTextInterface*>(this); + if (t == QAccessible::EditableTextInterface) + return static_cast<QAccessibleEditableTextInterface*>(this); + if (t == QAccessible::ValueInterface) + return static_cast<QAccessibleValueInterface*>(this); + if (t == QAccessible::TableCellInterface) + return static_cast<QAccessibleTableCellInterface*>(this); + if (t == QAccessible::TableInterface) + return static_cast<QAccessibleTableInterface*>(this); + return nullptr; +} + +bool QtAccessibleWidget::isValid() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + return xAc.is(); +} + +QObject* QtAccessibleWidget::object() const { return m_pObject; } + +void QtAccessibleWidget::setText(QAccessible::Text /* t */, const QString& /* text */) {} + +QAccessibleInterface* QtAccessibleWidget::childAt(int x, int y) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY); + return QAccessible::queryAccessibleInterface( + new QtXAccessible(xAccessibleComponent->getAccessibleAtPoint(awt::Point(x, y)))); +} + +QAccessibleInterface* QtAccessibleWidget::customFactory(const QString& classname, QObject* object) +{ + if (classname == QLatin1String("QtWidget") && object && object->isWidgetType()) + { + QtWidget* pWidget = static_cast<QtWidget*>(object); + vcl::Window* pWindow = pWidget->frame().GetWindow(); + + if (pWindow) + return new QtAccessibleWidget(pWindow->GetAccessible(), object); + } + if (classname == QLatin1String("QtXAccessible") && object) + { + QtXAccessible* pXAccessible = dynamic_cast<QtXAccessible*>(object); + if (pXAccessible && pXAccessible->m_xAccessible.is()) + return new QtAccessibleWidget(pXAccessible->m_xAccessible, object); + } + + return nullptr; +} + +// QAccessibleActionInterface +QStringList QtAccessibleWidget::actionNames() const +{ + QStringList actionNames; + Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY); + if (!xAccessibleAction.is()) + return actionNames; + + int count = xAccessibleAction->getAccessibleActionCount(); + for (int i = 0; i < count; i++) + { + OUString desc = xAccessibleAction->getAccessibleActionDescription(i); + actionNames.append(toQString(desc)); + } + return actionNames; +} + +void QtAccessibleWidget::doAction(const QString& actionName) +{ + Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY); + if (!xAccessibleAction.is()) + return; + + int index = actionNames().indexOf(actionName); + if (index == -1) + return; + xAccessibleAction->doAccessibleAction(index); +} + +QStringList QtAccessibleWidget::keyBindingsForAction(const QString& actionName) const +{ + QStringList keyBindings; + Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY); + if (!xAccessibleAction.is()) + return keyBindings; + + int index = actionNames().indexOf(actionName); + if (index == -1) + return keyBindings; + + Reference<XAccessibleKeyBinding> xKeyBinding + = xAccessibleAction->getAccessibleActionKeyBinding(index); + + if (!xKeyBinding.is()) + return keyBindings; + + int count = xKeyBinding->getAccessibleKeyBindingCount(); + for (int i = 0; i < count; i++) + { + Sequence<awt::KeyStroke> keyStroke = xKeyBinding->getAccessibleKeyBinding(i); + keyBindings.append(toQString(comphelper::GetkeyBindingStrByXkeyBinding(keyStroke))); + } + return keyBindings; +} + +// QAccessibleTextInterface +void QtAccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */) +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::addSelection"); +} + +namespace +{ +OUString lcl_convertFontWeight(double fontWeight) +{ + if (fontWeight == awt::FontWeight::THIN || fontWeight == awt::FontWeight::ULTRALIGHT) + return "100"; + if (fontWeight == awt::FontWeight::LIGHT) + return "200"; + if (fontWeight == awt::FontWeight::SEMILIGHT) + return "300"; + if (fontWeight == awt::FontWeight::NORMAL) + return "normal"; + if (fontWeight == awt::FontWeight::SEMIBOLD) + return "500"; + if (fontWeight == awt::FontWeight::BOLD) + return "bold"; + if (fontWeight == awt::FontWeight::ULTRABOLD) + return "800"; + if (fontWeight == awt::FontWeight::BLACK) + return "900"; + + // awt::FontWeight::DONTKNOW || fontWeight == awt::FontWeight::NORMAL + return "normal"; +} +} + +QString QtAccessibleWidget::attributes(int offset, int* startOffset, int* endOffset) const +{ + if (startOffset == nullptr || endOffset == nullptr) + return QString(); + + *startOffset = -1; + *endOffset = -1; + + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (!xText.is()) + return QString(); + + // handle special values for offset the same way base class's QAccessibleTextWidget::attributes does + // (as defined in IAccessible 2: -1 -> length, -2 -> cursor position) + if (offset == -2) + offset = cursorPosition(); + + const int nTextLength = characterCount(); + if (offset == -1 || offset == nTextLength) + offset = nTextLength - 1; + + if (offset < 0 || offset > nTextLength) + return QString(); + + const Sequence<PropertyValue> attribs + = xText->getCharacterAttributes(offset, Sequence<OUString>()); + OUString aRet; + for (PropertyValue const& prop : attribs) + { + OUString sAttribute; + OUString sValue; + if (prop.Name == "CharFontName") + { + sAttribute = "font-family"; + sValue = *o3tl::doAccess<OUString>(prop.Value); + } + else if (prop.Name == "CharHeight") + { + sAttribute = "font-size"; + sValue = OUString::number(*o3tl::doAccess<double>(prop.Value)) + "pt"; + } + else if (prop.Name == "CharWeight") + { + sAttribute = "font-weight"; + sValue = lcl_convertFontWeight(*o3tl::doAccess<double>(prop.Value)); + } + + if (!sAttribute.isEmpty() && !sValue.isEmpty()) + aRet += sAttribute + ":" + sValue + ";"; + } + *startOffset = offset; + *endOffset = offset + 1; + return toQString(aRet); +} + +int QtAccessibleWidget::characterCount() const +{ + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (xText.is()) + return xText->getCharacterCount(); + return 0; +} +QRect QtAccessibleWidget::characterRect(int /* offset */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::characterRect"); + return QRect(); +} + +int QtAccessibleWidget::cursorPosition() const +{ + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (xText.is()) + return xText->getCaretPosition(); + return 0; +} + +int QtAccessibleWidget::offsetAtPoint(const QPoint& /* point */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::offsetAtPoint"); + return 0; +} +void QtAccessibleWidget::removeSelection(int /* selectionIndex */) +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::removeSelection"); +} +void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex) +{ + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (xText.is()) + xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE); +} + +void QtAccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const +{ + if (!startOffset && !endOffset) + return; + + Reference<XAccessibleText> xText; + if (selectionIndex == 0) + xText = Reference<XAccessibleText>(getAccessibleContextImpl(), UNO_QUERY); + + if (startOffset) + *startOffset = xText.is() ? xText->getSelectionStart() : 0; + if (endOffset) + *endOffset = xText.is() ? xText->getSelectionEnd() : 0; +} + +int QtAccessibleWidget::selectionCount() const +{ + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (xText.is() && !xText->getSelectedText().isEmpty()) + return 1; // Only 1 selection supported atm + return 0; +} +void QtAccessibleWidget::setCursorPosition(int position) +{ + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (xText.is()) + xText->setCaretPosition(position); +} +void QtAccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset) +{ + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (xText.is()) + xText->setSelection(startOffset, endOffset); +} +QString QtAccessibleWidget::text(int startOffset, int endOffset) const +{ + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (xText.is()) + return toQString(xText->getTextRange(startOffset, endOffset)); + return QString(); +} +QString QtAccessibleWidget::textAfterOffset(int /* offset */, + QAccessible::TextBoundaryType /* boundaryType */, + int* /* startOffset */, int* /* endOffset */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textAfterOffset"); + return QString(); +} + +QString QtAccessibleWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, + int* startOffset, int* endOffset) const +{ + if (startOffset == nullptr || endOffset == nullptr) + return QString(); + + if (boundaryType == QAccessible::NoBoundary) + { + const int nCharCount = characterCount(); + *startOffset = 0; + *endOffset = nCharCount; + return text(0, nCharCount); + } + + Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); + if (!xText.is()) + return QString(); + + sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(boundaryType); + assert(nUnoBoundaryType > 0); + + const TextSegment segment = xText->getTextAtIndex(offset, nUnoBoundaryType); + *startOffset = segment.SegmentStart; + *endOffset = segment.SegmentEnd; + return toQString(segment.SegmentText); +} + +QString QtAccessibleWidget::textBeforeOffset(int /* offset */, + QAccessible::TextBoundaryType /* boundaryType */, + int* /* startOffset */, int* /* endOffset */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textBeforeOffset"); + return QString(); +} + +// QAccessibleEditableTextInterface + +void QtAccessibleWidget::deleteText(int startOffset, int endOffset) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); + if (!xEditableText.is()) + return; + xEditableText->deleteText(startOffset, endOffset); +} + +void QtAccessibleWidget::insertText(int offset, const QString& text) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); + if (!xEditableText.is()) + return; + xEditableText->insertText(toOUString(text), offset); +} + +void QtAccessibleWidget::replaceText(int startOffset, int endOffset, const QString& text) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); + if (!xEditableText.is()) + return; + xEditableText->replaceText(startOffset, endOffset, toOUString(text)); +} + +// QAccessibleValueInterface +QVariant QtAccessibleWidget::currentValue() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QVariant(); + + Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return QVariant(); + double aDouble = 0; + xValue->getCurrentValue() >>= aDouble; + return QVariant(aDouble); +} + +QVariant QtAccessibleWidget::maximumValue() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QVariant(); + + Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return QVariant(); + double aDouble = 0; + xValue->getMaximumValue() >>= aDouble; + return QVariant(aDouble); +} + +QVariant QtAccessibleWidget::minimumStepSize() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QVariant(); + + Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return QVariant(); + double dMinStep = 0; + xValue->getMinimumIncrement() >>= dMinStep; + return QVariant(dMinStep); +} + +QVariant QtAccessibleWidget::minimumValue() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QVariant(); + + Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return QVariant(); + double aDouble = 0; + xValue->getMinimumValue() >>= aDouble; + return QVariant(aDouble); +} + +void QtAccessibleWidget::setCurrentValue(const QVariant& value) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference<XAccessibleValue> xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return; + xValue->setCurrentValue(Any(value.toDouble())); +} + +// QAccessibleTable +QAccessibleInterface* QtAccessibleWidget::caption() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return nullptr; + return QAccessible::queryAccessibleInterface(new QtXAccessible(xTable->getAccessibleCaption())); +} + +QAccessibleInterface* QtAccessibleWidget::cellAt(int row, int column) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return nullptr; + return QAccessible::queryAccessibleInterface( + new QtXAccessible(xTable->getAccessibleCellAt(row, column))); +} + +int QtAccessibleWidget::columnCount() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getAccessibleColumnCount(); +} + +QString QtAccessibleWidget::columnDescription(int column) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QString(); + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QString(); + return toQString(xTable->getAccessibleColumnDescription(column)); +} + +bool QtAccessibleWidget::isColumnSelected(int nColumn) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return false; + + return xTable->isAccessibleColumnSelected(nColumn); +} + +bool QtAccessibleWidget::isRowSelected(int nRow) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return false; + + return xTable->isAccessibleRowSelected(nRow); +} + +void QtAccessibleWidget::modelChange(QAccessibleTableModelChangeEvent*) {} + +int QtAccessibleWidget::rowCount() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getAccessibleRowCount(); +} + +QString QtAccessibleWidget::rowDescription(int row) const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QString(); + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QString(); + return toQString(xTable->getAccessibleRowDescription(row)); +} + +bool QtAccessibleWidget::selectColumn(int column) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->selectColumn(column); +} + +bool QtAccessibleWidget::selectRow(int row) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->selectRow(row); +} + +int QtAccessibleWidget::selectedCellCount() const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCellCount"); + return 0; +} + +QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCells"); + return QList<QAccessibleInterface*>(); +} + +int QtAccessibleWidget::selectedColumnCount() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getSelectedAccessibleColumns().getLength(); +} + +QList<int> QtAccessibleWidget::selectedColumns() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QList<int>(); + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QList<int>(); + return toQList(xTable->getSelectedAccessibleColumns()); +} + +int QtAccessibleWidget::selectedRowCount() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getSelectedAccessibleRows().getLength(); +} + +QList<int> QtAccessibleWidget::selectedRows() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QList<int>(); + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QList<int>(); + return toQList(xTable->getSelectedAccessibleRows()); +} + +QAccessibleInterface* QtAccessibleWidget::summary() const +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference<XAccessibleTable> xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return nullptr; + return QAccessible::queryAccessibleInterface(new QtXAccessible(xTable->getAccessibleSummary())); +} + +bool QtAccessibleWidget::unselectColumn(int column) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->unselectColumn(column); +} + +bool QtAccessibleWidget::unselectRow(int row) +{ + Reference<XAccessibleContext> xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->unselectRow(row); +} + +QList<QAccessibleInterface*> QtAccessibleWidget::columnHeaderCells() const +{ + SAL_WARN("vcl.qt5", "Unsupported QAccessibleTableCellInterface::columnHeaderCells"); + return QList<QAccessibleInterface*>(); +} + +int QtAccessibleWidget::columnIndex() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return -1; + + Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); + if (!xTable.is()) + return -1; + + const sal_Int32 nIndexInParent = xAcc->getAccessibleIndexInParent(); + return xTable->getAccessibleColumn(nIndexInParent); +} + +bool QtAccessibleWidget::isSelected() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return false; + + Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); + if (!xTable.is()) + return false; + + const sal_Int32 nColumn = columnIndex(); + const sal_Int32 nRow = rowIndex(); + return xTable->isAccessibleSelected(nRow, nColumn); +} + +int QtAccessibleWidget::columnExtent() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return -1; + + Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); + if (!xTable.is()) + return -1; + + const sal_Int32 nColumn = columnIndex(); + const sal_Int32 nRow = rowIndex(); + return xTable->getAccessibleColumnExtentAt(nRow, nColumn); +} + +QList<QAccessibleInterface*> QtAccessibleWidget::rowHeaderCells() const +{ + SAL_WARN("vcl.qt5", "Unsupported QAccessibleTableCellInterface::rowHeaderCells"); + return QList<QAccessibleInterface*>(); +} + +int QtAccessibleWidget::rowExtent() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return -1; + + Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); + if (!xTable.is()) + return -1; + + const sal_Int32 nColumn = columnIndex(); + const sal_Int32 nRow = rowIndex(); + return xTable->getAccessibleRowExtentAt(nRow, nColumn); +} + +int QtAccessibleWidget::rowIndex() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return -1; + + Reference<XAccessibleTable> xTable = getAccessibleTableForParent(); + if (!xTable.is()) + return -1; + + const sal_Int32 nIndexInParent = xAcc->getAccessibleIndexInParent(); + return xTable->getAccessibleRow(nIndexInParent); +} + +QAccessibleInterface* QtAccessibleWidget::table() const +{ + SAL_WARN("vcl.qt5", "Unsupported QAccessibleTableCellInterface::table"); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtBitmap.cxx b/vcl/qt5/QtBitmap.cxx new file mode 100644 index 000000000000..0a9fb2b7812f --- /dev/null +++ b/vcl/qt5/QtBitmap.cxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtBitmap.hxx> +#include <QtTools.hxx> +#include <QtGraphics.hxx> + +#include <QtGui/QImage> +#include <QtCore/QVector> +#include <QtGui/QColor> + +#include <o3tl/safeint.hxx> +#include <sal/log.hxx> +#include <tools/helpers.hxx> + +QtBitmap::QtBitmap() {} + +QtBitmap::QtBitmap(const QImage& rImage) { m_pImage.reset(new QImage(rImage)); } + +bool QtBitmap::Create(const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal) +{ + if (ePixelFormat == vcl::PixelFormat::INVALID) + return false; + + if (ePixelFormat == vcl::PixelFormat::N1_BPP) + assert(2 >= rPal.GetEntryCount()); + if (ePixelFormat == vcl::PixelFormat::N8_BPP) + assert(256 >= rPal.GetEntryCount()); + + m_pImage.reset(new QImage(toQSize(rSize), getBitFormat(ePixelFormat))); + m_pImage->fill(Qt::transparent); + m_aPalette = rPal; + + auto count = rPal.GetEntryCount(); + if (count && m_pImage) + { + QVector<QRgb> aColorTable(count); + for (unsigned i = 0; i < count; ++i) + aColorTable[i] = qRgb(rPal[i].GetRed(), rPal[i].GetGreen(), rPal[i].GetBlue()); + m_pImage->setColorTable(aColorTable); + } + return true; +} + +bool QtBitmap::Create(const SalBitmap& rSalBmp) +{ + const QtBitmap* pBitmap = static_cast<const QtBitmap*>(&rSalBmp); + m_pImage.reset(new QImage(*pBitmap->m_pImage)); + m_aPalette = pBitmap->m_aPalette; + return true; +} + +bool QtBitmap::Create(const SalBitmap& rSalBmp, SalGraphics* pSalGraphics) +{ + const QtBitmap* pBitmap = static_cast<const QtBitmap*>(&rSalBmp); + QtGraphics* pGraphics = static_cast<QtGraphics*>(pSalGraphics); + QImage* pImage = pGraphics->getQImage(); + m_pImage.reset(new QImage(pBitmap->m_pImage->convertToFormat(pImage->format()))); + return true; +} + +bool QtBitmap::Create(const SalBitmap& rSalBmp, vcl::PixelFormat eNewPixelFormat) +{ + if (eNewPixelFormat == vcl::PixelFormat::INVALID) + return false; + const QtBitmap* pBitmap = static_cast<const QtBitmap*>(&rSalBmp); + m_pImage.reset(new QImage(pBitmap->m_pImage->convertToFormat(getBitFormat(eNewPixelFormat)))); + return true; +} + +bool QtBitmap::Create(const css::uno::Reference<css::rendering::XBitmapCanvas>& /*rBitmapCanvas*/, + Size& /*rSize*/, bool /*bMask*/) +{ + return false; +} + +void QtBitmap::Destroy() { m_pImage.reset(); } + +Size QtBitmap::GetSize() const +{ + if (m_pImage) + return toSize(m_pImage->size()); + return Size(); +} + +sal_uInt16 QtBitmap::GetBitCount() const +{ + if (m_pImage) + return getFormatBits(m_pImage->format()); + return 0; +} + +BitmapBuffer* QtBitmap::AcquireBuffer(BitmapAccessMode /*nMode*/) +{ + static const BitmapPalette aEmptyPalette; + + if (!m_pImage) + return nullptr; + + BitmapBuffer* pBuffer = new BitmapBuffer; + + pBuffer->mnWidth = m_pImage->width(); + pBuffer->mnHeight = m_pImage->height(); + pBuffer->mnBitCount = getFormatBits(m_pImage->format()); + pBuffer->mpBits = m_pImage->bits(); + pBuffer->mnScanlineSize = m_pImage->bytesPerLine(); + + switch (pBuffer->mnBitCount) + { + case 1: + pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal | ScanlineFormat::TopDown; + pBuffer->maPalette = m_aPalette; + break; + case 8: + pBuffer->mnFormat = ScanlineFormat::N8BitPal | ScanlineFormat::TopDown; + pBuffer->maPalette = m_aPalette; + break; + case 24: + pBuffer->mnFormat = ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown; + pBuffer->maPalette = aEmptyPalette; + break; + case 32: + { +#ifdef OSL_BIGENDIAN + pBuffer->mnFormat = ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown; +#else + pBuffer->mnFormat = ScanlineFormat::N32BitTcBgra | ScanlineFormat::TopDown; +#endif + pBuffer->maPalette = aEmptyPalette; + break; + } + default: + assert(false); + } + + return pBuffer; +} + +void QtBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) +{ + m_aPalette = pBuffer->maPalette; + auto count = m_aPalette.GetEntryCount(); + if (pBuffer->mnBitCount != 4 && count) + { + QVector<QRgb> aColorTable(count); + for (unsigned i = 0; i < count; ++i) + aColorTable[i] + = qRgb(m_aPalette[i].GetRed(), m_aPalette[i].GetGreen(), m_aPalette[i].GetBlue()); + m_pImage->setColorTable(aColorTable); + } + delete pBuffer; + if (nMode == BitmapAccessMode::Write) + InvalidateChecksum(); +} + +bool QtBitmap::GetSystemData(BitmapSystemData& /*rData*/) { return false; } + +bool QtBitmap::ScalingSupported() const { return false; } + +bool QtBitmap::Scale(const double& /*rScaleX*/, const double& /*rScaleY*/, + BmpScaleFlag /*nScaleFlag*/) +{ + return false; +} + +bool QtBitmap::Replace(const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, + sal_uInt8 /*nTol*/) +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtClipboard.cxx b/vcl/qt5/QtClipboard.cxx new file mode 100644 index 000000000000..f21e9d02aa50 --- /dev/null +++ b/vcl/qt5/QtClipboard.cxx @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 <QtClipboard.hxx> +#include <QtClipboard.moc> + +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> + +#include <QtWidgets/QApplication> + +#include <QtInstance.hxx> +#include <QtTransferable.hxx> +#include <QtTools.hxx> + +#include <cassert> +#include <map> + +QtClipboard::QtClipboard(const OUString& aModeString, const QClipboard::Mode aMode) + : cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard, + css::datatransfer::clipboard::XFlushableClipboard, + XServiceInfo>(m_aMutex) + , m_aClipboardName(aModeString) + , m_aClipboardMode(aMode) + , m_bOwnClipboardChange(false) + , m_bDoClear(false) +{ + assert(isSupported(m_aClipboardMode)); + // DirectConnection guarantees the changed slot runs in the same thread as the QClipboard + connect(QApplication::clipboard(), &QClipboard::changed, this, &QtClipboard::handleChanged, + Qt::DirectConnection); + + // explicitly queue an event, so we can eventually ignore it + connect(this, &QtClipboard::clearClipboard, this, &QtClipboard::handleClearClipboard, + Qt::QueuedConnection); +} + +css::uno::Reference<css::uno::XInterface> QtClipboard::create(const OUString& aModeString) +{ + static const std::map<OUString, QClipboard::Mode> aNameToClipboardMap + = { { "CLIPBOARD", QClipboard::Clipboard }, { "PRIMARY", QClipboard::Selection } }; + + assert(QApplication::clipboard()->thread() == qApp->thread()); + + auto iter = aNameToClipboardMap.find(aModeString); + if (iter != aNameToClipboardMap.end() && isSupported(iter->second)) + return static_cast<cppu::OWeakObject*>(new QtClipboard(aModeString, iter->second)); + SAL_WARN("vcl.qt5", "Ignoring unrecognized clipboard type: '" << aModeString << "'"); + return css::uno::Reference<css::uno::XInterface>(); +} + +void QtClipboard::flushClipboard() +{ + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([this]() { + if (!isOwner(m_aClipboardMode)) + return; + + QClipboard* pClipboard = QApplication::clipboard(); + const QtMimeData* pQtMimeData + = dynamic_cast<const QtMimeData*>(pClipboard->mimeData(m_aClipboardMode)); + assert(pQtMimeData); + + QMimeData* pMimeCopy = nullptr; + if (pQtMimeData && pQtMimeData->deepCopy(&pMimeCopy)) + { + m_bOwnClipboardChange = true; + pClipboard->setMimeData(pMimeCopy, m_aClipboardMode); + m_bOwnClipboardChange = false; + } + }); +} + +css::uno::Reference<css::datatransfer::XTransferable> QtClipboard::getContents() +{ + osl::MutexGuard aGuard(m_aMutex); + + // if we're the owner, we might have the XTransferable from setContents. but + // maybe a non-LO clipboard change from within LO, like some C'n'P in the + // QFileDialog, might have invalidated m_aContents, so we need to check it too. + if (isOwner(m_aClipboardMode) && m_aContents.is()) + return m_aContents; + + // check if we can still use the shared QtClipboardTransferable + const QMimeData* pMimeData = QApplication::clipboard()->mimeData(m_aClipboardMode); + if (m_aContents.is()) + { + const auto* pTrans = dynamic_cast<QtClipboardTransferable*>(m_aContents.get()); + assert(pTrans); + if (pTrans && pTrans->mimeData() == pMimeData) + return m_aContents; + } + + m_aContents = new QtClipboardTransferable(m_aClipboardMode, pMimeData); + return m_aContents; +} + +void QtClipboard::handleClearClipboard() +{ + if (!m_bDoClear) + return; + QApplication::clipboard()->clear(m_aClipboardMode); +} + +void QtClipboard::setContents( + const css::uno::Reference<css::datatransfer::XTransferable>& xTrans, + const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner) +{ + // it's actually possible to get a non-empty xTrans and an empty xClipboardOwner! + osl::ClearableMutexGuard aGuard(m_aMutex); + + css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner); + css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents); + m_aContents = xTrans; + m_aOwner = xClipboardOwner; + + m_bDoClear = !m_aContents.is(); + if (!m_bDoClear) + { + m_bOwnClipboardChange = true; + QApplication::clipboard()->setMimeData(new QtMimeData(m_aContents), m_aClipboardMode); + m_bOwnClipboardChange = false; + } + else + { + assert(!m_aOwner.is()); + Q_EMIT clearClipboard(); + } + + aGuard.clear(); + + // we have to notify only an owner change, since handleChanged can't + // access the previous owner anymore and can just handle lost ownership. + if (xOldOwner.is() && xOldOwner != xClipboardOwner) + xOldOwner->lostOwnership(this, xOldContents); +} + +void QtClipboard::handleChanged(QClipboard::Mode aMode) +{ + if (aMode != m_aClipboardMode) + return; + + osl::ClearableMutexGuard aGuard(m_aMutex); + + // QtWayland will send a second change notification (seemingly without any + // trigger). And any C'n'P operation in the Qt file picker emits a signal, + // with LO still holding the clipboard ownership, but internally having lost + // it. So ignore any signal, which still delivers the internal QtMimeData + // as the clipboard content and is no "advertised" change. + if (!m_bOwnClipboardChange && isOwner(aMode) + && dynamic_cast<const QtMimeData*>(QApplication::clipboard()->mimeData(aMode))) + return; + + css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner); + css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents); + // ownership change from LO POV is handled in setContents + if (!m_bOwnClipboardChange) + { + m_aContents.clear(); + m_aOwner.clear(); + } + + std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> aListeners( + m_aListeners); + css::datatransfer::clipboard::ClipboardEvent aEv; + aEv.Contents = getContents(); + + aGuard.clear(); + + if (!m_bOwnClipboardChange && xOldOwner.is()) + xOldOwner->lostOwnership(this, xOldContents); + for (auto const& listener : aListeners) + listener->changedContents(aEv); +} + +OUString QtClipboard::getImplementationName() { return "com.sun.star.datatransfer.QtClipboard"; } + +css::uno::Sequence<OUString> QtClipboard::getSupportedServiceNames() +{ + return { "com.sun.star.datatransfer.clipboard.SystemClipboard" }; +} + +sal_Bool QtClipboard::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +OUString QtClipboard::getName() { return m_aClipboardName; } + +sal_Int8 QtClipboard::getRenderingCapabilities() { return 0; } + +void QtClipboard::addClipboardListener( + const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) +{ + osl::MutexGuard aGuard(m_aMutex); + m_aListeners.push_back(listener); +} + +void QtClipboard::removeClipboardListener( + const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) +{ + osl::MutexGuard aGuard(m_aMutex); + m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener), + m_aListeners.end()); +} + +bool QtClipboard::isSupported(const QClipboard::Mode aMode) +{ + const QClipboard* pClipboard = QApplication::clipboard(); + switch (aMode) + { + case QClipboard::Selection: + return pClipboard->supportsSelection(); + + case QClipboard::FindBuffer: + return pClipboard->supportsFindBuffer(); + + case QClipboard::Clipboard: + return true; + } + return false; +} + +bool QtClipboard::isOwner(const QClipboard::Mode aMode) +{ + if (!isSupported(aMode)) + return false; + + const QClipboard* pClipboard = QApplication::clipboard(); + switch (aMode) + { + case QClipboard::Selection: + return pClipboard->ownsSelection(); + + case QClipboard::FindBuffer: + return pClipboard->ownsFindBuffer(); + + case QClipboard::Clipboard: + return pClipboard->ownsClipboard(); + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtData.cxx b/vcl/qt5/QtData.cxx new file mode 100644 index 000000000000..dc435fdbd358 --- /dev/null +++ b/vcl/qt5/QtData.cxx @@ -0,0 +1,337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtData.hxx> + +#include <QtGui/QBitmap> +#include <QtGui/QCursor> +#include <QtWidgets/QApplication> +#include <QtWidgets/QStyle> + +#include <sal/log.hxx> + +#include <unx/x11_cursors/ase_curs.h> +#include <unx/x11_cursors/ase_mask.h> +#include <unx/x11_cursors/asn_curs.h> +#include <unx/x11_cursors/asn_mask.h> +#include <unx/x11_cursors/asne_curs.h> +#include <unx/x11_cursors/asne_mask.h> +#include <unx/x11_cursors/asns_curs.h> +#include <unx/x11_cursors/asns_mask.h> +#include <unx/x11_cursors/asnswe_curs.h> +#include <unx/x11_cursors/asnswe_mask.h> +#include <unx/x11_cursors/asnw_curs.h> +#include <unx/x11_cursors/asnw_mask.h> +#include <unx/x11_cursors/ass_curs.h> +#include <unx/x11_cursors/ass_mask.h> +#include <unx/x11_cursors/asse_curs.h> +#include <unx/x11_cursors/asse_mask.h> +#include <unx/x11_cursors/assw_curs.h> +#include <unx/x11_cursors/assw_mask.h> +#include <unx/x11_cursors/asw_curs.h> +#include <unx/x11_cursors/asw_mask.h> +#include <unx/x11_cursors/aswe_curs.h> +#include <unx/x11_cursors/aswe_mask.h> +#include <unx/x11_cursors/chain_curs.h> +#include <unx/x11_cursors/chain_mask.h> +#include <unx/x11_cursors/chainnot_curs.h> +#include <unx/x11_cursors/chainnot_mask.h> +#include <unx/x11_cursors/chart_curs.h> +#include <unx/x11_cursors/chart_mask.h> +#include <unx/x11_cursors/copydata_curs.h> +#include <unx/x11_cursors/copydata_mask.h> +#include <unx/x11_cursors/copydlnk_curs.h> +#include <unx/x11_cursors/copydlnk_mask.h> +#include <unx/x11_cursors/copyfile_curs.h> +#include <unx/x11_cursors/copyfile_mask.h> +#include <unx/x11_cursors/copyfiles_curs.h> +#include <unx/x11_cursors/copyfiles_mask.h> +#include <unx/x11_cursors/copyflnk_curs.h> +#include <unx/x11_cursors/copyflnk_mask.h> +#include <unx/x11_cursors/crook_curs.h> +#include <unx/x11_cursors/crook_mask.h> +#include <unx/x11_cursors/crop_curs.h> +#include <unx/x11_cursors/crop_mask.h> +#include <unx/x11_cursors/detective_curs.h> +#include <unx/x11_cursors/detective_mask.h> +#include <unx/x11_cursors/drawarc_curs.h> +#include <unx/x11_cursors/drawarc_mask.h> +#include <unx/x11_cursors/drawbezier_curs.h> +#include <unx/x11_cursors/drawbezier_mask.h> +#include <unx/x11_cursors/drawcaption_curs.h> +#include <unx/x11_cursors/drawcaption_mask.h> +#include <unx/x11_cursors/drawcirclecut_curs.h> +#include <unx/x11_cursors/drawcirclecut_mask.h> +#include <unx/x11_cursors/drawconnect_curs.h> +#include <unx/x11_cursors/drawconnect_mask.h> +#include <unx/x11_cursors/drawellipse_curs.h> +#include <unx/x11_cursors/drawellipse_mask.h> +#include <unx/x11_cursors/drawfreehand_curs.h> +#include <unx/x11_cursors/drawfreehand_mask.h> +#include <unx/x11_cursors/drawline_curs.h> +#include <unx/x11_cursors/drawline_mask.h> +#include <unx/x11_cursors/drawpie_curs.h> +#include <unx/x11_cursors/drawpie_mask.h> +#include <unx/x11_cursors/drawpolygon_curs.h> +#include <unx/x11_cursors/drawpolygon_mask.h> +#include <unx/x11_cursors/drawrect_curs.h> +#include <unx/x11_cursors/drawrect_mask.h> +#include <unx/x11_cursors/drawtext_curs.h> +#include <unx/x11_cursors/drawtext_mask.h> +#include <unx/x11_cursors/fill_curs.h> +#include <unx/x11_cursors/fill_mask.h> +#include <unx/x11_cursors/hshear_curs.h> +#include <unx/x11_cursors/hshear_mask.h> +#include <unx/x11_cursors/linkdata_curs.h> +#include <unx/x11_cursors/linkdata_mask.h> +#include <unx/x11_cursors/linkfile_curs.h> +#include <unx/x11_cursors/linkfile_mask.h> +#include <unx/x11_cursors/magnify_curs.h> +#include <unx/x11_cursors/magnify_mask.h> +#include <unx/x11_cursors/mirror_curs.h> +#include <unx/x11_cursors/mirror_mask.h> +#include <unx/x11_cursors/movebezierweight_curs.h> +#include <unx/x11_cursors/movebezierweight_mask.h> +#include <unx/x11_cursors/movedata_curs.h> +#include <unx/x11_cursors/movedata_mask.h> +#include <unx/x11_cursors/movedlnk_curs.h> +#include <unx/x11_cursors/movedlnk_mask.h> +#include <unx/x11_cursors/movefile_curs.h> +#include <unx/x11_cursors/movefile_mask.h> +#include <unx/x11_cursors/movefiles_curs.h> +#include <unx/x11_cursors/movefiles_mask.h> +#include <unx/x11_cursors/moveflnk_curs.h> +#include <unx/x11_cursors/moveflnk_mask.h> +#include <unx/x11_cursors/movepoint_curs.h> +#include <unx/x11_cursors/movepoint_mask.h> +#include <unx/x11_cursors/nodrop_curs.h> +#include <unx/x11_cursors/nodrop_mask.h> +#include <unx/x11_cursors/pivotcol_curs.h> +#include <unx/x11_cursors/pivotcol_mask.h> +#include <unx/x11_cursors/pivotdel_curs.h> +#include <unx/x11_cursors/pivotdel_mask.h> +#include <unx/x11_cursors/pivotfld_curs.h> +#include <unx/x11_cursors/pivotfld_mask.h> +#include <unx/x11_cursors/pivotrow_curs.h> +#include <unx/x11_cursors/pivotrow_mask.h> +#include <unx/x11_cursors/rotate_curs.h> +#include <unx/x11_cursors/rotate_mask.h> +#include <unx/x11_cursors/tblsele_curs.h> +#include <unx/x11_cursors/tblsele_mask.h> +#include <unx/x11_cursors/tblsels_curs.h> +#include <unx/x11_cursors/tblsels_mask.h> +#include <unx/x11_cursors/tblselse_curs.h> +#include <unx/x11_cursors/tblselse_mask.h> +#include <unx/x11_cursors/tblselsw_curs.h> +#include <unx/x11_cursors/tblselsw_mask.h> +#include <unx/x11_cursors/tblselw_curs.h> +#include <unx/x11_cursors/tblselw_mask.h> +#include <unx/x11_cursors/vertcurs_curs.h> +#include <unx/x11_cursors/vertcurs_mask.h> +#include <unx/x11_cursors/vshear_curs.h> +#include <unx/x11_cursors/vshear_mask.h> +#include <unx/x11_cursors/wshide_curs.h> +#include <unx/x11_cursors/wshide_mask.h> +#include <unx/x11_cursors/wsshow_curs.h> +#include <unx/x11_cursors/wsshow_mask.h> +#include <unx/x11_cursors/fatcross_curs.h> +#include <unx/x11_cursors/fatcross_mask.h> + +#include <unx/glyphcache.hxx> + +QtData::QtData(SalInstance* pInstance) + : GenericUnixSalData(pInstance) +{ + ImplSVData* pSVData = ImplGetSVData(); + + pSVData->maNWFData.mbDockingAreaSeparateTB = true; + pSVData->maNWFData.mbFlatMenu = true; + pSVData->maNWFData.mbRolloverMenubar = true; + pSVData->maNWFData.mbNoFocusRects = true; + pSVData->maNWFData.mbNoFocusRectsForFlatButtons = true; + + QStyle* style = QApplication::style(); + pSVData->maNWFData.mnMenuFormatBorderX = style->pixelMetric(QStyle::PM_MenuPanelWidth) + + style->pixelMetric(QStyle::PM_MenuHMargin); + pSVData->maNWFData.mnMenuFormatBorderY = style->pixelMetric(QStyle::PM_MenuPanelWidth) + + style->pixelMetric(QStyle::PM_MenuVMargin); +} + +// outline dtor b/c of FreetypeManager incomplete type +QtData::~QtData() {} + +static QCursor* getQCursorFromXBM(const unsigned char* pBitmap, const unsigned char* pMask, + int nWidth, int nHeight, int nXHot, int nYHot) +{ + QBitmap aPixmap = QBitmap::fromData(QSize(nWidth, nHeight), pBitmap); + QBitmap aMask = QBitmap::fromData(QSize(nWidth, nHeight), pMask); + return new QCursor(aPixmap, aMask, nXHot, nYHot); +} +#define MAKE_CURSOR(vcl_name, name) \ + case vcl_name: \ + pCursor = getQCursorFromXBM(name##curs##_bits, name##mask##_bits, name##curs_width, \ + name##curs_height, name##curs_x_hot, name##curs_y_hot); \ + break + +#define MAP_BUILTIN(vcl_name, qt_enum) \ + case vcl_name: \ + pCursor = new QCursor(qt_enum); \ + break + +QCursor& QtData::getCursor(PointerStyle ePointerStyle) +{ + if (!m_aCursors[ePointerStyle]) + { + QCursor* pCursor = nullptr; + + switch (ePointerStyle) + { + MAP_BUILTIN(PointerStyle::Arrow, Qt::ArrowCursor); + MAP_BUILTIN(PointerStyle::Text, Qt::IBeamCursor); + MAP_BUILTIN(PointerStyle::Help, Qt::WhatsThisCursor); + MAP_BUILTIN(PointerStyle::Cross, Qt::CrossCursor); + MAP_BUILTIN(PointerStyle::Wait, Qt::WaitCursor); + MAP_BUILTIN(PointerStyle::NSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::SSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::WSize, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::ESize, Qt::SizeHorCursor); + + MAP_BUILTIN(PointerStyle::NWSize, Qt::SizeFDiagCursor); + MAP_BUILTIN(PointerStyle::NESize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::SWSize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::SESize, Qt::SizeFDiagCursor); + MAP_BUILTIN(PointerStyle::WindowNSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::WindowSSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::WindowWSize, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::WindowESize, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::WindowNWSize, Qt::SizeFDiagCursor); + MAP_BUILTIN(PointerStyle::WindowNESize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::WindowSWSize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::WindowSESize, Qt::SizeFDiagCursor); + + MAP_BUILTIN(PointerStyle::HSizeBar, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::VSizeBar, Qt::SizeVerCursor); + + MAP_BUILTIN(PointerStyle::RefHand, Qt::OpenHandCursor); + MAP_BUILTIN(PointerStyle::Hand, Qt::OpenHandCursor); +#if 0 + MAP_BUILTIN( PointerStyle::Pen, GDK_PENCIL ); +#endif + MAP_BUILTIN(PointerStyle::HSplit, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::VSplit, Qt::SizeVerCursor); + + MAP_BUILTIN(PointerStyle::Move, Qt::SizeAllCursor); + + MAP_BUILTIN(PointerStyle::Null, Qt::BlankCursor); + MAKE_CURSOR(PointerStyle::Magnify, magnify_); + MAKE_CURSOR(PointerStyle::Fill, fill_); + MAKE_CURSOR(PointerStyle::MoveData, movedata_); + MAKE_CURSOR(PointerStyle::CopyData, copydata_); + MAKE_CURSOR(PointerStyle::MoveFile, movefile_); + MAKE_CURSOR(PointerStyle::CopyFile, copyfile_); + MAKE_CURSOR(PointerStyle::MoveFiles, movefiles_); + MAKE_CURSOR(PointerStyle::CopyFiles, copyfiles_); + MAKE_CURSOR(PointerStyle::NotAllowed, nodrop_); + MAKE_CURSOR(PointerStyle::Rotate, rotate_); + MAKE_CURSOR(PointerStyle::HShear, hshear_); + MAKE_CURSOR(PointerStyle::VShear, vshear_); + MAKE_CURSOR(PointerStyle::DrawLine, drawline_); + MAKE_CURSOR(PointerStyle::DrawRect, drawrect_); + MAKE_CURSOR(PointerStyle::DrawPolygon, drawpolygon_); + MAKE_CURSOR(PointerStyle::DrawBezier, drawbezier_); + MAKE_CURSOR(PointerStyle::DrawArc, drawarc_); + MAKE_CURSOR(PointerStyle::DrawPie, drawpie_); + MAKE_CURSOR(PointerStyle::DrawCircleCut, drawcirclecut_); + MAKE_CURSOR(PointerStyle::DrawEllipse, drawellipse_); + MAKE_CURSOR(PointerStyle::DrawConnect, drawconnect_); + MAKE_CURSOR(PointerStyle::DrawText, drawtext_); + MAKE_CURSOR(PointerStyle::Mirror, mirror_); + MAKE_CURSOR(PointerStyle::Crook, crook_); + MAKE_CURSOR(PointerStyle::Crop, crop_); + MAKE_CURSOR(PointerStyle::MovePoint, movepoint_); + MAKE_CURSOR(PointerStyle::MoveBezierWeight, movebezierweight_); + MAKE_CURSOR(PointerStyle::DrawFreehand, drawfreehand_); + MAKE_CURSOR(PointerStyle::DrawCaption, drawcaption_); + MAKE_CURSOR(PointerStyle::LinkData, linkdata_); + MAKE_CURSOR(PointerStyle::MoveDataLink, movedlnk_); + MAKE_CURSOR(PointerStyle::CopyDataLink, copydlnk_); + MAKE_CURSOR(PointerStyle::LinkFile, linkfile_); + MAKE_CURSOR(PointerStyle::MoveFileLink, moveflnk_); + MAKE_CURSOR(PointerStyle::CopyFileLink, copyflnk_); + MAKE_CURSOR(PointerStyle::Chart, chart_); + MAKE_CURSOR(PointerStyle::Detective, detective_); + MAKE_CURSOR(PointerStyle::PivotCol, pivotcol_); + MAKE_CURSOR(PointerStyle::PivotRow, pivotrow_); + MAKE_CURSOR(PointerStyle::PivotField, pivotfld_); + MAKE_CURSOR(PointerStyle::PivotDelete, pivotdel_); + MAKE_CURSOR(PointerStyle::Chain, chain_); + MAKE_CURSOR(PointerStyle::ChainNotAllowed, chainnot_); + MAKE_CURSOR(PointerStyle::AutoScrollN, asn_); + MAKE_CURSOR(PointerStyle::AutoScrollS, ass_); + MAKE_CURSOR(PointerStyle::AutoScrollW, asw_); + MAKE_CURSOR(PointerStyle::AutoScrollE, ase_); + MAKE_CURSOR(PointerStyle::AutoScrollNW, asnw_); + MAKE_CURSOR(PointerStyle::AutoScrollNE, asne_); + MAKE_CURSOR(PointerStyle::AutoScrollSW, assw_); + MAKE_CURSOR(PointerStyle::AutoScrollSE, asse_); + MAKE_CURSOR(PointerStyle::AutoScrollNS, asns_); + MAKE_CURSOR(PointerStyle::AutoScrollWE, aswe_); + MAKE_CURSOR(PointerStyle::AutoScrollNSWE, asnswe_); + MAKE_CURSOR(PointerStyle::TextVertical, vertcurs_); + + MAKE_CURSOR(PointerStyle::TabSelectS, tblsels_); + MAKE_CURSOR(PointerStyle::TabSelectE, tblsele_); + MAKE_CURSOR(PointerStyle::TabSelectSE, tblselse_); + MAKE_CURSOR(PointerStyle::TabSelectW, tblselw_); + MAKE_CURSOR(PointerStyle::TabSelectSW, tblselsw_); + + MAKE_CURSOR(PointerStyle::HideWhitespace, hidewhitespace_); + MAKE_CURSOR(PointerStyle::ShowWhitespace, showwhitespace_); + + MAKE_CURSOR(PointerStyle::FatCross, fatcross_); + default: + break; + } + if (!pCursor) + { + pCursor = new QCursor(Qt::ArrowCursor); + SAL_WARN("vcl.qt5", + "pointer " << static_cast<int>(ePointerStyle) << " not implemented"); + } + + m_aCursors[ePointerStyle].reset(pCursor); + } + + return *m_aCursors[ePointerStyle]; +} + +void QtData::ErrorTrapPush() {} + +bool QtData::ErrorTrapPop(bool /*bIgnoreError*/) { return false; } + +bool QtData::noNativeControls() +{ + static const bool bNoNative + = ((nullptr != getenv("SAL_VCL_QT5_NO_NATIVE")) && (nullptr != ImplGetSVData()) + && ImplGetSVData()->maAppData.mxToolkitName + && ImplGetSVData()->maAppData.mxToolkitName->match("qt5")); + return bNoNative; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtDragAndDrop.cxx b/vcl/qt5/QtDragAndDrop.cxx new file mode 100644 index 000000000000..e05993718753 --- /dev/null +++ b/vcl/qt5/QtDragAndDrop.cxx @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/datatransfer/DataFlavor.hpp> +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> + +#include <QtDragAndDrop.hxx> +#include <QtFrame.hxx> +#include <QtTransferable.hxx> +#include <QtWidget.hxx> + +#include <QtGui/QDrag> + +using namespace com::sun::star; + +QtDragSource::~QtDragSource() {} + +void QtDragSource::deinitialize() { m_pFrame = nullptr; } + +sal_Bool QtDragSource::isDragImageSupported() { return true; } + +sal_Int32 QtDragSource::getDefaultCursor(sal_Int8) { return 0; } + +void QtDragSource::initialize(const css::uno::Sequence<css::uno::Any>& rArguments) +{ + if (rArguments.getLength() < 2) + { + throw uno::RuntimeException("DragSource::initialize: Cannot install window event handler", + static_cast<OWeakObject*>(this)); + } + + sal_IntPtr nFrame = 0; + rArguments.getConstArray()[1] >>= nFrame; + + if (!nFrame) + { + throw uno::RuntimeException("DragSource::initialize: missing SalFrame", + static_cast<OWeakObject*>(this)); + } + + m_pFrame = reinterpret_cast<QtFrame*>(nFrame); + m_pFrame->registerDragSource(this); +} + +void QtDragSource::startDrag( + const datatransfer::dnd::DragGestureEvent& /*rEvent*/, sal_Int8 sourceActions, + sal_Int32 /*cursor*/, sal_Int32 /*image*/, + const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, + const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener) +{ + m_xListener = rListener; + + if (m_pFrame) + { + QDrag* drag = new QDrag(m_pFrame->GetQWidget()); + drag->setMimeData(new QtMimeData(rTrans)); + // just a reminder that exec starts a nested event loop, so everything after + // this call is just executed, after D'n'D has finished! + drag->exec(toQtDropActions(sourceActions), getPreferredDropAction(sourceActions)); + } + + // the drop will eventually call fire_dragEnd, which will clear the listener. + // if D'n'D ends without success, we just get a leave event without any indicator, + // but the event loop will be terminated, so we have to try to inform the source of + // a failure in any way. + fire_dragEnd(datatransfer::dnd::DNDConstants::ACTION_NONE, false); +} + +void QtDragSource::fire_dragEnd(sal_Int8 nAction, bool bDropSuccessful) +{ + if (!m_xListener.is()) + return; + + datatransfer::dnd::DragSourceDropEvent aEv; + aEv.DropAction = nAction; + aEv.DropSuccess = bDropSuccessful; + + auto xListener = m_xListener; + m_xListener.clear(); + xListener->dragDropEnd(aEv); +} + +OUString SAL_CALL QtDragSource::getImplementationName() +{ + return "com.sun.star.datatransfer.dnd.VclQtDragSource"; +} + +sal_Bool SAL_CALL QtDragSource::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL QtDragSource::getSupportedServiceNames() +{ + return { "com.sun.star.datatransfer.dnd.QtDragSource" }; +} + +QtDropTarget::QtDropTarget() + : WeakComponentImplHelper(m_aMutex) + , m_pFrame(nullptr) + , m_bActive(false) + , m_nDefaultActions(0) +{ +} + +OUString SAL_CALL QtDropTarget::getImplementationName() +{ + return "com.sun.star.datatransfer.dnd.VclQtDropTarget"; +} + +sal_Bool SAL_CALL QtDropTarget::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence<OUString> SAL_CALL QtDropTarget::getSupportedServiceNames() +{ + return { "com.sun.star.datatransfer.dnd.QtDropTarget" }; +} + +QtDropTarget::~QtDropTarget() {} + +void QtDropTarget::deinitialize() +{ + m_pFrame = nullptr; + m_bActive = false; +} + +void QtDropTarget::initialize(const uno::Sequence<uno::Any>& rArguments) +{ + if (rArguments.getLength() < 2) + { + throw uno::RuntimeException("DropTarget::initialize: Cannot install window event handler", + static_cast<OWeakObject*>(this)); + } + + sal_IntPtr nFrame = 0; + rArguments.getConstArray()[1] >>= nFrame; + + if (!nFrame) + { + throw uno::RuntimeException("DropTarget::initialize: missing SalFrame", + static_cast<OWeakObject*>(this)); + } + + m_nDropAction = datatransfer::dnd::DNDConstants::ACTION_NONE; + + m_pFrame = reinterpret_cast<QtFrame*>(nFrame); + m_pFrame->registerDropTarget(this); + m_bActive = true; +} + +void QtDropTarget::addDropTargetListener( + const uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) +{ + ::osl::Guard<::osl::Mutex> aGuard(m_aMutex); + + m_aListeners.push_back(xListener); +} + +void QtDropTarget::removeDropTargetListener( + const uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) +{ + ::osl::Guard<::osl::Mutex> aGuard(m_aMutex); + + m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), xListener), + m_aListeners.end()); +} + +sal_Bool QtDropTarget::isActive() { return m_bActive; } + +void QtDropTarget::setActive(sal_Bool bActive) { m_bActive = bActive; } + +sal_Int8 QtDropTarget::getDefaultActions() { return m_nDefaultActions; } + +void QtDropTarget::setDefaultActions(sal_Int8 nDefaultActions) +{ + m_nDefaultActions = nDefaultActions; +} + +void QtDropTarget::fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde) +{ + osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + { + listener->dragEnter(dtde); + } +} + +void QtDropTarget::fire_dragOver(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde) +{ + osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + listener->dragOver(dtde); +} + +void QtDropTarget::fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) +{ + m_bDropSuccessful = true; + + osl::ClearableGuard<osl::Mutex> aGuard(m_aMutex); + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + listener->drop(dtde); +} + +void QtDropTarget::fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte) +{ + osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); + std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + listener->dragExit(dte); +} + +void QtDropTarget::acceptDrag(sal_Int8 dragOperation) { m_nDropAction = dragOperation; } + +void QtDropTarget::rejectDrag() { m_nDropAction = 0; } + +void QtDropTarget::acceptDrop(sal_Int8 dropOperation) { m_nDropAction = dropOperation; } + +void QtDropTarget::rejectDrop() { m_nDropAction = 0; } + +void QtDropTarget::dropComplete(sal_Bool success) +{ + m_bDropSuccessful = (m_bDropSuccessful && success); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtFilePicker.cxx b/vcl/qt5/QtFilePicker.cxx new file mode 100644 index 000000000000..eda2579c1c58 --- /dev/null +++ b/vcl/qt5/QtFilePicker.cxx @@ -0,0 +1,945 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtFilePicker.hxx> +#include <QtFilePicker.moc> + +#include <QtFrame.hxx> +#include <QtTools.hxx> +#include <QtWidget.hxx> +#include <QtInstance.hxx> + +#include <com/sun/star/awt/SystemDependentXWindow.hpp> +#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/TerminationVetoException.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/SystemDependent.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ControlActions.hpp> +#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp> +#include <cppuhelper/interfacecontainer.h> +#include <cppuhelper/supportsservice.hxx> +#include <rtl/process.h> +#include <sal/log.hxx> + +#include <QtCore/QDebug> +#include <QtCore/QRegularExpression> +#include <QtCore/QThread> +#include <QtCore/QUrl> +#include <QtGui/QClipboard> +#include <QtGui/QWindow> +#include <QtWidgets/QApplication> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QComboBox> +#include <QtWidgets/QGridLayout> +#include <QtWidgets/QHBoxLayout> +#include <QtWidgets/QLabel> +#include <QtWidgets/QMessageBox> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QWidget> + +#include <unx/geninst.h> +#include <strings.hrc> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::ui::dialogs::TemplateDescription; +using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds; +using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; + +namespace +{ +uno::Sequence<OUString> FilePicker_getSupportedServiceNames() +{ + return { "com.sun.star.ui.dialogs.FilePicker", "com.sun.star.ui.dialogs.SystemFilePicker", + "com.sun.star.ui.dialogs.QtFilePicker" }; +} +} + +QtFilePicker::QtFilePicker(css::uno::Reference<css::uno::XComponentContext> const& context, + QFileDialog::FileMode eMode, bool bUseNative) + : QtFilePicker_Base(m_aHelperMutex) + , m_context(context) + , m_bIsFolderPicker(eMode == QFileDialog::Directory) + , m_pParentWidget(nullptr) + , m_pFileDialog(new QFileDialog(nullptr, {}, QDir::homePath())) + , m_pExtraControls(new QWidget()) +{ + m_pFileDialog->setOption(QFileDialog::DontUseNativeDialog, !bUseNative); + + m_pFileDialog->setFileMode(eMode); + m_pFileDialog->setWindowModality(Qt::ApplicationModal); + + if (m_bIsFolderPicker) + { + m_pFileDialog->setOption(QFileDialog::ShowDirsOnly, true); + m_pFileDialog->setWindowTitle(toQString(VclResId(STR_FPICKER_FOLDER_DEFAULT_TITLE))); + } + + m_pLayout = dynamic_cast<QGridLayout*>(m_pFileDialog->layout()); + + setMultiSelectionMode(false); + + // XFilePickerListener notifications + connect(m_pFileDialog.get(), SIGNAL(filterSelected(const QString&)), this, + SLOT(filterSelected(const QString&))); + connect(m_pFileDialog.get(), SIGNAL(currentChanged(const QString&)), this, + SLOT(currentChanged(const QString&))); + + // update automatic file extension when filter is changed + connect(m_pFileDialog.get(), SIGNAL(filterSelected(const QString&)), this, + SLOT(updateAutomaticFileExtension())); +} + +QtFilePicker::~QtFilePicker() +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this]() { + // must delete it in main thread, otherwise + // QSocketNotifier::setEnabled() will crash us + m_pFileDialog.reset(); + }); +} + +void SAL_CALL +QtFilePicker::addFilePickerListener(const uno::Reference<XFilePickerListener>& xListener) +{ + SolarMutexGuard aGuard; + m_xListener = xListener; +} + +void SAL_CALL QtFilePicker::removeFilePickerListener(const uno::Reference<XFilePickerListener>&) +{ + SolarMutexGuard aGuard; + m_xListener.clear(); +} + +void SAL_CALL QtFilePicker::setTitle(const OUString& title) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread( + [this, &title]() { m_pFileDialog->setWindowTitle(toQString(title)); }); +} + +sal_Int16 SAL_CALL QtFilePicker::execute() +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + sal_uInt16 ret; + pSalInst->RunInMainThread([&ret, this]() { ret = execute(); }); + return ret; + } + + QWidget* pTransientParent = m_pParentWidget; + if (!pTransientParent) + { + vcl::Window* pWindow = ::Application::GetActiveTopWindow(); + if (pWindow) + { + QtFrame* pFrame = dynamic_cast<QtFrame*>(pWindow->ImplGetFrame()); + assert(pFrame); + if (pFrame) + pTransientParent = pFrame->asChild(); + } + } + + if (!m_aNamedFilterList.isEmpty()) + m_pFileDialog->setNameFilters(m_aNamedFilterList); + if (!m_aCurrentFilter.isEmpty()) + m_pFileDialog->selectNameFilter(m_aCurrentFilter); + + updateAutomaticFileExtension(); + + uno::Reference<css::frame::XDesktop> xDesktop(css::frame::Desktop::create(m_context), + UNO_QUERY_THROW); + + // will hide the window, so do before show + m_pFileDialog->setParent(pTransientParent, m_pFileDialog->windowFlags()); + m_pFileDialog->show(); + xDesktop->addTerminateListener(this); + int result = m_pFileDialog->exec(); + xDesktop->removeTerminateListener(this); + m_pFileDialog->setParent(nullptr, m_pFileDialog->windowFlags()); + + if (QFileDialog::Rejected == result) + return ExecutableDialogResults::CANCEL; + return ExecutableDialogResults::OK; +} + +void SAL_CALL QtFilePicker::setMultiSelectionMode(sal_Bool multiSelect) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, multiSelect]() { + if (m_bIsFolderPicker || m_pFileDialog->acceptMode() == QFileDialog::AcceptSave) + return; + + m_pFileDialog->setFileMode(multiSelect ? QFileDialog::ExistingFiles + : QFileDialog::ExistingFile); + }); +} + +void SAL_CALL QtFilePicker::setDefaultName(const OUString& name) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, &name]() { m_pFileDialog->selectFile(toQString(name)); }); +} + +void SAL_CALL QtFilePicker::setDisplayDirectory(const OUString& dir) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, &dir]() { + QString qDir(toQString(dir)); + m_pFileDialog->setDirectoryUrl(QUrl(qDir)); + }); +} + +OUString SAL_CALL QtFilePicker::getDisplayDirectory() +{ + SolarMutexGuard g; + OUString ret; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread( + [&ret, this]() { ret = toOUString(m_pFileDialog->directoryUrl().toString()); }); + return ret; +} + +uno::Sequence<OUString> SAL_CALL QtFilePicker::getFiles() +{ + uno::Sequence<OUString> seq = getSelectedFiles(); + if (seq.getLength() > 1) + seq.realloc(1); + return seq; +} + +uno::Sequence<OUString> SAL_CALL QtFilePicker::getSelectedFiles() +{ + SolarMutexGuard g; + QList<QUrl> urls; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([&urls, this]() { urls = m_pFileDialog->selectedUrls(); }); + + uno::Sequence<OUString> seq(urls.size()); + + auto const trans = css::uri::ExternalUriReferenceTranslator::create(m_context); + size_t i = 0; + for (const QUrl& aURL : urls) + { + // Unlike LO, QFileDialog (<https://doc.qt.io/qt-5/qfiledialog.html>) apparently always + // treats file-system pathnames as UTF-8--encoded, regardless of LANG/LC_CTYPE locale + // setting. And pathnames containing byte sequences that are not valid UTF-8 are apparently + // filtered out and not even displayed by QFileDialog, so aURL will always have a "payload" + // that matches the pathname's byte sequence. So the pathname's byte sequence (which + // happens to also be aURL's payload) in the LANG/LC_CTYPE encoding needs to be converted + // into LO's internal UTF-8 file URL encoding via + // XExternalUriReferenceTranslator::translateToInternal (which looks somewhat paradoxical as + // aURL.toEncoded() nominally already has a UTF-8 payload): + auto const extUrl = toOUString(aURL.toEncoded()); + auto intUrl = trans->translateToInternal(extUrl); + if (intUrl.isEmpty()) + { + // If translation failed, fall back to original URL: + SAL_WARN("vcl.qt5", "cannot convert <" << extUrl << "> from locale encoding to UTF-8"); + intUrl = extUrl; + } + seq[i++] = intUrl; + } + + return seq; +} + +void SAL_CALL QtFilePicker::appendFilter(const OUString& title, const OUString& filter) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, &title, &filter]() { appendFilter(title, filter); }); + return; + } + + // '/' need to be escaped else they are assumed to be mime types + QString sTitle = toQString(title).replace("/", "\\/"); + + QString sFilterName = sTitle; + // the Qt non-native file picker adds the extensions to the filter title, so strip them + if (m_pFileDialog->testOption(QFileDialog::DontUseNativeDialog)) + { + int pos = sFilterName.indexOf(" ("); + if (pos >= 0) + sFilterName.truncate(pos); + } + + QString sGlobFilter = toQString(filter); + + // LibreOffice gives us filters separated by ';' qt dialogs just want space separated + sGlobFilter.replace(";", " "); + + // make sure "*.*" is not used as "all files" + sGlobFilter.replace("*.*", "*"); + + m_aNamedFilterList << QStringLiteral("%1 (%2)").arg(sFilterName, sGlobFilter); + m_aTitleToFilterMap[sTitle] = m_aNamedFilterList.constLast(); + m_aNamedFilterToExtensionMap[m_aNamedFilterList.constLast()] = sGlobFilter; +} + +void SAL_CALL QtFilePicker::setCurrentFilter(const OUString& title) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, &title]() { + m_aCurrentFilter = m_aTitleToFilterMap.value(toQString(title).replace("/", "\\/")); + }); +} + +OUString SAL_CALL QtFilePicker::getCurrentFilter() +{ + SolarMutexGuard g; + QString filter; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([&filter, this]() { + filter = m_aTitleToFilterMap.key(m_pFileDialog->selectedNameFilter()); + }); + + if (filter.isEmpty()) + filter = "ODF Text Document (.odt)"; + return toOUString(filter); +} + +void SAL_CALL QtFilePicker::appendFilterGroup(const OUString& rGroupTitle, + const uno::Sequence<beans::StringPair>& filters) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread( + [this, &rGroupTitle, &filters]() { appendFilterGroup(rGroupTitle, filters); }); + return; + } + + const sal_uInt16 length = filters.getLength(); + for (sal_uInt16 i = 0; i < length; ++i) + { + beans::StringPair aPair = filters[i]; + appendFilter(aPair.First, aPair.Second); + } +} + +uno::Any QtFilePicker::handleGetListValue(const QComboBox* pWidget, sal_Int16 nControlAction) +{ + uno::Any aAny; + switch (nControlAction) + { + case ControlActions::GET_ITEMS: + { + Sequence<OUString> aItemList(pWidget->count()); + for (sal_Int32 i = 0; i < pWidget->count(); ++i) + aItemList[i] = toOUString(pWidget->itemText(i)); + aAny <<= aItemList; + break; + } + case ControlActions::GET_SELECTED_ITEM: + { + if (!pWidget->currentText().isEmpty()) + aAny <<= toOUString(pWidget->currentText()); + break; + } + case ControlActions::GET_SELECTED_ITEM_INDEX: + { + if (pWidget->currentIndex() >= 0) + aAny <<= static_cast<sal_Int32>(pWidget->currentIndex()); + break; + } + default: + SAL_WARN("vcl.qt5", + "undocumented/unimplemented ControlAction for a list " << nControlAction); + break; + } + return aAny; +} + +void QtFilePicker::handleSetListValue(QComboBox* pWidget, sal_Int16 nControlAction, + const uno::Any& rValue) +{ + switch (nControlAction) + { + case ControlActions::ADD_ITEM: + { + OUString sItem; + rValue >>= sItem; + pWidget->addItem(toQString(sItem)); + break; + } + case ControlActions::ADD_ITEMS: + { + Sequence<OUString> aStringList; + rValue >>= aStringList; + for (auto const& sItem : std::as_const(aStringList)) + pWidget->addItem(toQString(sItem)); + break; + } + case ControlActions::DELETE_ITEM: + { + sal_Int32 nPos = 0; + rValue >>= nPos; + pWidget->removeItem(nPos); + break; + } + case ControlActions::DELETE_ITEMS: + { + pWidget->clear(); + break; + } + case ControlActions::SET_SELECT_ITEM: + { + sal_Int32 nPos = 0; + rValue >>= nPos; + pWidget->setCurrentIndex(nPos); + break; + } + default: + SAL_WARN("vcl.qt5", + "undocumented/unimplemented ControlAction for a list " << nControlAction); + break; + } + + pWidget->setEnabled(pWidget->count() > 0); +} + +void SAL_CALL QtFilePicker::setValue(sal_Int16 controlId, sal_Int16 nControlAction, + const uno::Any& value) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, controlId, nControlAction, &value]() { + setValue(controlId, nControlAction, value); + }); + return; + } + + if (m_aCustomWidgetsMap.contains(controlId)) + { + QWidget* widget = m_aCustomWidgetsMap.value(controlId); + QCheckBox* cb = dynamic_cast<QCheckBox*>(widget); + if (cb) + cb->setChecked(value.get<bool>()); + else + { + QComboBox* combo = dynamic_cast<QComboBox*>(widget); + if (combo) + handleSetListValue(combo, nControlAction, value); + } + } + else + SAL_WARN("vcl.qt5", "set value on unknown control " << controlId); +} + +uno::Any SAL_CALL QtFilePicker::getValue(sal_Int16 controlId, sal_Int16 nControlAction) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + uno::Any ret; + pSalInst->RunInMainThread([&ret, this, controlId, nControlAction]() { + ret = getValue(controlId, nControlAction); + }); + return ret; + } + + uno::Any res(false); + if (m_aCustomWidgetsMap.contains(controlId)) + { + QWidget* widget = m_aCustomWidgetsMap.value(controlId); + QCheckBox* cb = dynamic_cast<QCheckBox*>(widget); + if (cb) + res <<= cb->isChecked(); + else + { + QComboBox* combo = dynamic_cast<QComboBox*>(widget); + if (combo) + res = handleGetListValue(combo, nControlAction); + } + } + else + SAL_WARN("vcl.qt5", "get value on unknown control " << controlId); + + return res; +} + +void SAL_CALL QtFilePicker::enableControl(sal_Int16 controlId, sal_Bool enable) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, controlId, enable]() { + if (m_aCustomWidgetsMap.contains(controlId)) + m_aCustomWidgetsMap.value(controlId)->setEnabled(enable); + else + SAL_WARN("vcl.qt5", "enable unknown control " << controlId); + }); +} + +void SAL_CALL QtFilePicker::setLabel(sal_Int16 controlId, const OUString& label) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, controlId, label]() { setLabel(controlId, label); }); + return; + } + + if (m_aCustomWidgetsMap.contains(controlId)) + { + QCheckBox* cb = dynamic_cast<QCheckBox*>(m_aCustomWidgetsMap.value(controlId)); + if (cb) + cb->setText(toQString(label)); + } + else + SAL_WARN("vcl.qt5", "set label on unknown control " << controlId); +} + +OUString SAL_CALL QtFilePicker::getLabel(sal_Int16 controlId) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + OUString ret; + pSalInst->RunInMainThread([&ret, this, controlId]() { ret = getLabel(controlId); }); + return ret; + } + + QString label; + if (m_aCustomWidgetsMap.contains(controlId)) + { + QCheckBox* cb = dynamic_cast<QCheckBox*>(m_aCustomWidgetsMap.value(controlId)); + if (cb) + label = cb->text(); + } + else + SAL_WARN("vcl.qt5", "get label on unknown control " << controlId); + + return toOUString(label); +} + +QString QtFilePicker::getResString(TranslateId pResId) +{ + QString aResString; + + if (!pResId) + return aResString; + + aResString = toQString(VclResId(pResId)); + + return aResString.replace('~', '&'); +} + +void QtFilePicker::addCustomControl(sal_Int16 controlId) +{ + QWidget* widget = nullptr; + QLabel* label = nullptr; + TranslateId resId; + QCheckBox* pCheckbox = nullptr; + + switch (controlId) + { + case CHECKBOX_AUTOEXTENSION: + resId = STR_FPICKER_AUTO_EXTENSION; + break; + case CHECKBOX_PASSWORD: + resId = STR_FPICKER_PASSWORD; + break; + case CHECKBOX_FILTEROPTIONS: + resId = STR_FPICKER_FILTER_OPTIONS; + break; + case CHECKBOX_READONLY: + resId = STR_FPICKER_READONLY; + break; + case CHECKBOX_LINK: + resId = STR_FPICKER_INSERT_AS_LINK; + break; + case CHECKBOX_PREVIEW: + resId = STR_FPICKER_SHOW_PREVIEW; + break; + case CHECKBOX_SELECTION: + resId = STR_FPICKER_SELECTION; + break; + case CHECKBOX_GPGENCRYPTION: + resId = STR_FPICKER_GPGENCRYPT; + break; + case PUSHBUTTON_PLAY: + resId = STR_FPICKER_PLAY; + break; + case LISTBOX_VERSION: + resId = STR_FPICKER_VERSION; + break; + case LISTBOX_TEMPLATE: + resId = STR_FPICKER_TEMPLATES; + break; + case LISTBOX_IMAGE_TEMPLATE: + resId = STR_FPICKER_IMAGE_TEMPLATE; + break; + case LISTBOX_IMAGE_ANCHOR: + resId = STR_FPICKER_IMAGE_ANCHOR; + break; + case LISTBOX_VERSION_LABEL: + case LISTBOX_TEMPLATE_LABEL: + case LISTBOX_IMAGE_TEMPLATE_LABEL: + case LISTBOX_IMAGE_ANCHOR_LABEL: + case LISTBOX_FILTER_SELECTOR: + break; + } + + switch (controlId) + { + case CHECKBOX_AUTOEXTENSION: + pCheckbox = new QCheckBox(getResString(resId), m_pExtraControls); + // to add/remove automatic file extension based on checkbox + connect(pCheckbox, SIGNAL(stateChanged(int)), this, + SLOT(updateAutomaticFileExtension())); + widget = pCheckbox; + break; + case CHECKBOX_PASSWORD: + case CHECKBOX_FILTEROPTIONS: + case CHECKBOX_READONLY: + case CHECKBOX_LINK: + case CHECKBOX_PREVIEW: + case CHECKBOX_SELECTION: + case CHECKBOX_GPGENCRYPTION: + widget = new QCheckBox(getResString(resId), m_pExtraControls); + break; + case PUSHBUTTON_PLAY: + break; + case LISTBOX_VERSION: + case LISTBOX_TEMPLATE: + case LISTBOX_IMAGE_ANCHOR: + case LISTBOX_IMAGE_TEMPLATE: + case LISTBOX_FILTER_SELECTOR: + label = new QLabel(getResString(resId), m_pExtraControls); + widget = new QComboBox(m_pExtraControls); + label->setBuddy(widget); + break; + case LISTBOX_VERSION_LABEL: + case LISTBOX_TEMPLATE_LABEL: + case LISTBOX_IMAGE_TEMPLATE_LABEL: + case LISTBOX_IMAGE_ANCHOR_LABEL: + break; + } + + if (widget) + { + const int row = m_pLayout->rowCount(); + if (label) + m_pLayout->addWidget(label, row, 0); + m_pLayout->addWidget(widget, row, 1); + m_aCustomWidgetsMap.insert(controlId, widget); + } +} + +void SAL_CALL QtFilePicker::initialize(const uno::Sequence<uno::Any>& args) +{ + // parameter checking + uno::Any arg; + if (args.getLength() == 0) + throw lang::IllegalArgumentException("no arguments", static_cast<XFilePicker2*>(this), 1); + + arg = args[0]; + + if ((arg.getValueType() != cppu::UnoType<sal_Int16>::get()) + && (arg.getValueType() != cppu::UnoType<sal_Int8>::get())) + { + throw lang::IllegalArgumentException("invalid argument type", + static_cast<XFilePicker2*>(this), 1); + } + + SolarMutexGuard g; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, args]() { initialize(args); }); + return; + } + + m_aNamedFilterToExtensionMap.clear(); + m_aNamedFilterList.clear(); + m_aTitleToFilterMap.clear(); + m_aCurrentFilter.clear(); + + sal_Int16 templateId = -1; + arg >>= templateId; + + QFileDialog::AcceptMode acceptMode = QFileDialog::AcceptOpen; + switch (templateId) + { + case FILEOPEN_SIMPLE: + break; + + case FILESAVE_SIMPLE: + acceptMode = QFileDialog::AcceptSave; + break; + + case FILESAVE_AUTOEXTENSION: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + break; + + case FILESAVE_AUTOEXTENSION_PASSWORD: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(CHECKBOX_PASSWORD); + addCustomControl(CHECKBOX_GPGENCRYPTION); + break; + + case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(CHECKBOX_PASSWORD); + addCustomControl(CHECKBOX_GPGENCRYPTION); + addCustomControl(CHECKBOX_FILTEROPTIONS); + break; + + case FILESAVE_AUTOEXTENSION_SELECTION: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(CHECKBOX_SELECTION); + break; + + case FILESAVE_AUTOEXTENSION_TEMPLATE: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(LISTBOX_TEMPLATE); + break; + + case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE: + addCustomControl(CHECKBOX_LINK); + addCustomControl(CHECKBOX_PREVIEW); + addCustomControl(LISTBOX_IMAGE_TEMPLATE); + break; + + case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR: + addCustomControl(CHECKBOX_LINK); + addCustomControl(CHECKBOX_PREVIEW); + addCustomControl(LISTBOX_IMAGE_ANCHOR); + break; + + case FILEOPEN_PLAY: + addCustomControl(PUSHBUTTON_PLAY); + break; + + case FILEOPEN_LINK_PLAY: + addCustomControl(CHECKBOX_LINK); + addCustomControl(PUSHBUTTON_PLAY); + break; + + case FILEOPEN_READONLY_VERSION: + addCustomControl(CHECKBOX_READONLY); + addCustomControl(LISTBOX_VERSION); + break; + + case FILEOPEN_LINK_PREVIEW: + addCustomControl(CHECKBOX_LINK); + addCustomControl(CHECKBOX_PREVIEW); + break; + + case FILEOPEN_PREVIEW: + addCustomControl(CHECKBOX_PREVIEW); + break; + + default: + throw lang::IllegalArgumentException("Unknown template", + static_cast<XFilePicker2*>(this), 1); + } + + TranslateId resId; + switch (acceptMode) + { + case QFileDialog::AcceptOpen: + resId = STR_FPICKER_OPEN; + break; + case QFileDialog::AcceptSave: + resId = STR_FPICKER_SAVE; + m_pFileDialog->setFileMode(QFileDialog::AnyFile); + break; + } + + m_pFileDialog->setAcceptMode(acceptMode); + m_pFileDialog->setWindowTitle(getResString(resId)); + + css::uno::Reference<css::awt::XWindow> xParentWindow; + if (args.getLength() > 1) + args[1] >>= xParentWindow; + if (!xParentWindow.is()) + return; + + css::uno::Reference<css::awt::XSystemDependentWindowPeer> xSysWinPeer(xParentWindow, + css::uno::UNO_QUERY); + if (!xSysWinPeer.is()) + return; + + // the sal_*Int8 handling is strange, but it's public API - no way around + css::uno::Sequence<sal_Int8> aProcessIdent(16); + rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8*>(aProcessIdent.getArray())); + uno::Any aAny + = xSysWinPeer->getWindowHandle(aProcessIdent, css::lang::SystemDependent::SYSTEM_XWINDOW); + css::awt::SystemDependentXWindow xSysWin; + aAny >>= xSysWin; + + const auto& pFrames = pSalInst->getFrames(); + const tools::Long aWindowHandle = xSysWin.WindowHandle; + const auto it + = std::find_if(pFrames.begin(), pFrames.end(), [&aWindowHandle](auto pFrame) -> bool { + const SystemEnvData* pData = pFrame->GetSystemData(); + return pData && tools::Long(pData->GetWindowHandle(pFrame)) == aWindowHandle; + }); + if (it != pFrames.end()) + m_pParentWidget = static_cast<QtFrame*>(*it)->asChild(); +} + +void SAL_CALL QtFilePicker::cancel() { m_pFileDialog->reject(); } + +void SAL_CALL QtFilePicker::disposing(const lang::EventObject& rEvent) +{ + uno::Reference<XFilePickerListener> xFilePickerListener(rEvent.Source, uno::UNO_QUERY); + + if (xFilePickerListener.is()) + { + removeFilePickerListener(xFilePickerListener); + } +} + +void SAL_CALL QtFilePicker::queryTermination(const css::lang::EventObject&) +{ + throw css::frame::TerminationVetoException(); +} + +void SAL_CALL QtFilePicker::notifyTermination(const css::lang::EventObject&) +{ + SolarMutexGuard aGuard; + m_pFileDialog->reject(); +} + +OUString SAL_CALL QtFilePicker::getImplementationName() +{ + return "com.sun.star.ui.dialogs.QtFilePicker"; +} + +sal_Bool SAL_CALL QtFilePicker::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +uno::Sequence<OUString> SAL_CALL QtFilePicker::getSupportedServiceNames() +{ + return FilePicker_getSupportedServiceNames(); +} + +void QtFilePicker::updateAutomaticFileExtension() +{ + bool bSetAutoExtension + = getValue(CHECKBOX_AUTOEXTENSION, ControlActions::GET_SELECTED_ITEM).get<bool>(); + if (bSetAutoExtension) + { + QString sSuffix = m_aNamedFilterToExtensionMap.value(m_pFileDialog->selectedNameFilter()); + // string is "*.<SUFFIX>" if a specific filter was selected that has exactly one possible file extension + if (sSuffix.lastIndexOf("*.") == 0) + { + sSuffix = sSuffix.remove("*."); + m_pFileDialog->setDefaultSuffix(sSuffix); + } + else + { + // fall back to setting none otherwise + SAL_INFO( + "vcl.qt5", + "Unable to retrieve unambiguous file extension. Will not add any automatically."); + bSetAutoExtension = false; + } + } + + if (!bSetAutoExtension) + m_pFileDialog->setDefaultSuffix(""); +} + +void QtFilePicker::filterSelected(const QString&) +{ + FilePickerEvent aEvent; + aEvent.ElementId = LISTBOX_FILTER; + SAL_INFO("vcl.qt5", "filter changed"); + if (m_xListener.is()) + m_xListener->controlStateChanged(aEvent); +} + +void QtFilePicker::currentChanged(const QString&) +{ + FilePickerEvent aEvent; + SAL_INFO("vcl.qt5", "file selection changed"); + if (m_xListener.is()) + m_xListener->fileSelectionChanged(aEvent); +} + +OUString QtFilePicker::getDirectory() +{ + uno::Sequence<OUString> seq = getSelectedFiles(); + if (seq.getLength() > 1) + seq.realloc(1); + return seq[0]; +} + +void QtFilePicker::setDescription(const OUString&) {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtFont.cxx b/vcl/qt5/QtFont.cxx new file mode 100644 index 000000000000..8079576f156f --- /dev/null +++ b/vcl/qt5/QtFont.cxx @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <QtFont.hxx> +#include <QtTools.hxx> + +#include <QtGui/QFont> +#include <QtGui/QRawFont> + +static inline void applyWeight(QtFont& rFont, FontWeight eWeight) +{ + switch (eWeight) + { + case WEIGHT_THIN: + rFont.setWeight(QFont::Thin); + break; + case WEIGHT_ULTRALIGHT: + rFont.setWeight(QFont::ExtraLight); + break; + case WEIGHT_LIGHT: + rFont.setWeight(QFont::Light); + break; + case WEIGHT_SEMILIGHT: + [[fallthrough]]; + case WEIGHT_NORMAL: + rFont.setWeight(QFont::Normal); + break; + case WEIGHT_MEDIUM: + rFont.setWeight(QFont::Medium); + break; + case WEIGHT_SEMIBOLD: + rFont.setWeight(QFont::DemiBold); + break; + case WEIGHT_BOLD: + rFont.setWeight(QFont::Bold); + break; + case WEIGHT_ULTRABOLD: + rFont.setWeight(QFont::ExtraBold); + break; + case WEIGHT_BLACK: + rFont.setWeight(QFont::Black); + break; + default: + break; + } +} + +static inline void applyStretch(QtFont& rFont, FontWidth eWidthType) +{ + switch (eWidthType) + { + case WIDTH_DONTKNOW: + rFont.setStretch(QFont::AnyStretch); + break; + case WIDTH_ULTRA_CONDENSED: + rFont.setStretch(QFont::UltraCondensed); + break; + case WIDTH_EXTRA_CONDENSED: + rFont.setStretch(QFont::ExtraCondensed); + break; + case WIDTH_CONDENSED: + rFont.setStretch(QFont::Condensed); + break; + case WIDTH_SEMI_CONDENSED: + rFont.setStretch(QFont::SemiCondensed); + break; + case WIDTH_NORMAL: + rFont.setStretch(QFont::Unstretched); + break; + case WIDTH_SEMI_EXPANDED: + rFont.setStretch(QFont::SemiExpanded); + break; + case WIDTH_EXPANDED: + rFont.setStretch(QFont::Expanded); + break; + case WIDTH_EXTRA_EXPANDED: + rFont.setStretch(QFont::ExtraExpanded); + break; + case WIDTH_ULTRA_EXPANDED: + rFont.setStretch(QFont::UltraExpanded); + break; + default: + break; + } +} + +static inline void applyStyle(QtFont& rFont, FontItalic eItalic) +{ + switch (eItalic) + { + case ITALIC_NONE: + rFont.setStyle(QFont::Style::StyleNormal); + break; + case ITALIC_OBLIQUE: + rFont.setStyle(QFont::Style::StyleOblique); + break; + case ITALIC_NORMAL: + rFont.setStyle(QFont::Style::StyleItalic); + break; + default: + break; + } +} + +QtFont::QtFont(const PhysicalFontFace& rPFF, const vcl::font::FontSelectPattern& rFSP) + : LogicalFontInstance(rPFF, rFSP) +{ + setFamily(toQString(rPFF.GetFamilyName())); + applyWeight(*this, rPFF.GetWeight()); + setPixelSize(rFSP.mnHeight); + applyStretch(*this, rPFF.GetWidthType()); + applyStyle(*this, rFSP.GetItalic()); +} + +static hb_blob_t* getFontTable(hb_face_t*, hb_tag_t nTableTag, void* pUserData) +{ + char pTagName[5]; + LogicalFontInstance::DecodeOpenTypeTag(nTableTag, pTagName); + + QtFont* pFont = static_cast<QtFont*>(pUserData); + QRawFont aRawFont(QRawFont::fromFont(*pFont)); + QByteArray aTable = aRawFont.fontTable(pTagName); + const sal_uInt32 nLength = aTable.size(); + + hb_blob_t* pBlob = nullptr; + if (nLength > 0) + pBlob = hb_blob_create(aTable.data(), nLength, HB_MEMORY_MODE_DUPLICATE, nullptr, nullptr); + return pBlob; +} + +hb_font_t* QtFont::ImplInitHbFont() +{ + return InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr)); +} + +bool QtFont::GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const { return false; } + +bool QtFont::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool) const +{ + QRawFont aRawFont(QRawFont::fromFont(*this)); + rRect = toRectangle(aRawFont.boundingRect(nId).toAlignedRect()); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtFontFace.cxx b/vcl/qt5/QtFontFace.cxx new file mode 100644 index 000000000000..0eb51bf850b6 --- /dev/null +++ b/vcl/qt5/QtFontFace.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 <sal/config.h> + +#include <unotools/fontdefs.hxx> + +#include <QtFontFace.hxx> +#include <QtFont.hxx> +#include <QtTools.hxx> + +#include <sft.hxx> +#include <impfontcharmap.hxx> +#include <fontinstance.hxx> +#include <font/FontSelectPattern.hxx> +#include <PhysicalFontCollection.hxx> + +#include <QtGui/QFont> +#include <QtGui/QFontDatabase> +#include <QtGui/QFontInfo> +#include <QtGui/QRawFont> + +using namespace vcl; + +QtFontFace::QtFontFace(const QtFontFace& rSrc) + : PhysicalFontFace(rSrc) + , m_aFontId(rSrc.m_aFontId) + , m_eFontIdType(rSrc.m_eFontIdType) +{ + if (rSrc.m_xCharMap.is()) + m_xCharMap = rSrc.m_xCharMap; +} + +FontWeight QtFontFace::toFontWeight(const int nWeight) +{ + if (nWeight <= QFont::Thin) + return WEIGHT_THIN; + if (nWeight <= QFont::ExtraLight) + return WEIGHT_ULTRALIGHT; + if (nWeight <= QFont::Light) + return WEIGHT_LIGHT; + if (nWeight <= QFont::Normal) + return WEIGHT_NORMAL; + if (nWeight <= QFont::Medium) + return WEIGHT_MEDIUM; + if (nWeight <= QFont::DemiBold) + return WEIGHT_SEMIBOLD; + if (nWeight <= QFont::Bold) + return WEIGHT_BOLD; + if (nWeight <= QFont::ExtraBold) + return WEIGHT_ULTRABOLD; + return WEIGHT_BLACK; +} + +FontWidth QtFontFace::toFontWidth(const int nStretch) +{ + if (nStretch == 0) // QFont::AnyStretch since Qt 5.8 + return WIDTH_DONTKNOW; + if (nStretch <= QFont::UltraCondensed) + return WIDTH_ULTRA_CONDENSED; + if (nStretch <= QFont::ExtraCondensed) + return WIDTH_EXTRA_CONDENSED; + if (nStretch <= QFont::Condensed) + return WIDTH_CONDENSED; + if (nStretch <= QFont::SemiCondensed) + return WIDTH_SEMI_CONDENSED; + if (nStretch <= QFont::Unstretched) + return WIDTH_NORMAL; + if (nStretch <= QFont::SemiExpanded) + return WIDTH_SEMI_EXPANDED; + if (nStretch <= QFont::Expanded) + return WIDTH_EXPANDED; + if (nStretch <= QFont::ExtraExpanded) + return WIDTH_EXTRA_EXPANDED; + return WIDTH_ULTRA_EXPANDED; +} + +FontItalic QtFontFace::toFontItalic(const QFont::Style eStyle) +{ + switch (eStyle) + { + case QFont::StyleNormal: + return ITALIC_NONE; + case QFont::StyleItalic: + return ITALIC_NORMAL; + case QFont::StyleOblique: + return ITALIC_OBLIQUE; + } + + return ITALIC_NONE; +} + +void QtFontFace::fillAttributesFromQFont(const QFont& rFont, FontAttributes& rFA) +{ + QFontInfo aFontInfo(rFont); + + rFA.SetFamilyName(toOUString(aFontInfo.family())); + if (IsStarSymbol(toOUString(aFontInfo.family()))) + rFA.SetSymbolFlag(true); + rFA.SetStyleName(toOUString(aFontInfo.styleName())); + rFA.SetPitch(aFontInfo.fixedPitch() ? PITCH_FIXED : PITCH_VARIABLE); + rFA.SetWeight(QtFontFace::toFontWeight(aFontInfo.weight())); + rFA.SetItalic(QtFontFace::toFontItalic(aFontInfo.style())); + rFA.SetWidthType(QtFontFace::toFontWidth(rFont.stretch())); +} + +QtFontFace* QtFontFace::fromQFont(const QFont& rFont) +{ + FontAttributes aFA; + fillAttributesFromQFont(rFont, aFA); + return new QtFontFace(aFA, rFont.toString(), FontIdType::Font); +} + +QtFontFace* QtFontFace::fromQFontDatabase(const QString& aFamily, const QString& aStyle) +{ + QFontDatabase aFDB; + FontAttributes aFA; + + aFA.SetFamilyName(toOUString(aFamily)); + if (IsStarSymbol(aFA.GetFamilyName())) + aFA.SetSymbolFlag(true); + aFA.SetStyleName(toOUString(aStyle)); + aFA.SetPitch(aFDB.isFixedPitch(aFamily, aStyle) ? PITCH_FIXED : PITCH_VARIABLE); + aFA.SetWeight(QtFontFace::toFontWeight(aFDB.weight(aFamily, aStyle))); + aFA.SetItalic(aFDB.italic(aFamily, aStyle) ? ITALIC_NORMAL : ITALIC_NONE); + + int nPointSize = 0; + QList<int> aPointList = aFDB.pointSizes(aFamily, aStyle); + if (!aPointList.empty()) + nPointSize = aPointList[0]; + + return new QtFontFace(aFA, aFamily + "," + aStyle + "," + QString::number(nPointSize), + FontIdType::FontDB); +} + +QtFontFace::QtFontFace(const FontAttributes& rFA, const QString& rFontID, + const FontIdType eFontIdType) + : PhysicalFontFace(rFA) + , m_aFontId(rFontID) + , m_eFontIdType(eFontIdType) + , m_bFontCapabilitiesRead(false) +{ +} + +sal_IntPtr QtFontFace::GetFontId() const { return reinterpret_cast<sal_IntPtr>(&m_aFontId); } + +QFont QtFontFace::CreateFont() const +{ + QFont aFont; + switch (m_eFontIdType) + { + case FontDB: + { + QFontDatabase aFDB; + QStringList aStrList = m_aFontId.split(","); + if (3 == aStrList.size()) + aFont = aFDB.font(aStrList[0], aStrList[1], aStrList[2].toInt()); + else + SAL_WARN("vcl.qt5", "Invalid QFontDatabase font ID " << m_aFontId); + break; + } + case Font: + bool bRet = aFont.fromString(m_aFontId); + SAL_WARN_IF(!bRet, "vcl.qt5", "Failed to create QFont from ID: " << m_aFontId); + Q_UNUSED(bRet); + break; + } + return aFont; +} + +rtl::Reference<LogicalFontInstance> +QtFontFace::CreateFontInstance(const vcl::font::FontSelectPattern& rFSD) const +{ + return new QtFont(*this, rFSD); +} + +FontCharMapRef QtFontFace::GetFontCharMap() const +{ + if (m_xCharMap.is()) + return m_xCharMap; + + QFont aFont = CreateFont(); + QRawFont aRawFont(QRawFont::fromFont(aFont)); + QByteArray aCMapTable = aRawFont.fontTable("cmap"); + if (aCMapTable.isEmpty()) + { + m_xCharMap = new FontCharMap(); + return m_xCharMap; + } + + CmapResult aCmapResult; + if (ParseCMAP(reinterpret_cast<const unsigned char*>(aCMapTable.data()), aCMapTable.size(), + aCmapResult)) + m_xCharMap = new FontCharMap(aCmapResult); + + return m_xCharMap; +} + +bool QtFontFace::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const +{ + // read this only once per font + if (m_bFontCapabilitiesRead) + { + rFontCapabilities = m_aFontCapabilities; + return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; + } + m_bFontCapabilitiesRead = true; + + QFont aFont = CreateFont(); + QRawFont aRawFont(QRawFont::fromFont(aFont)); + QByteArray aOS2Table = aRawFont.fontTable("OS/2"); + if (!aOS2Table.isEmpty()) + { + vcl::getTTCoverage(m_aFontCapabilities.oUnicodeRange, m_aFontCapabilities.oCodePageRange, + reinterpret_cast<const unsigned char*>(aOS2Table.data()), + aOS2Table.size()); + } + + rFontCapabilities = m_aFontCapabilities; + return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtFrame.cxx b/vcl/qt5/QtFrame.cxx new file mode 100644 index 000000000000..23a051e75862 --- /dev/null +++ b/vcl/qt5/QtFrame.cxx @@ -0,0 +1,1452 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtFrame.hxx> +#include <QtFrame.moc> + +#include <QtData.hxx> +#include <QtDragAndDrop.hxx> +#include <QtGraphics.hxx> +#include <QtInstance.hxx> +#include <QtMainWindow.hxx> +#include <QtMenu.hxx> +#include <QtSvpGraphics.hxx> +#include <QtSystem.hxx> +#include <QtTools.hxx> +#include <QtTransferable.hxx> +#include <QtWidget.hxx> + +#include <QtCore/QMimeData> +#include <QtCore/QPoint> +#include <QtCore/QSize> +#include <QtCore/QThread> +#include <QtCore/QVersionNumber> +#include <QtGui/QDragMoveEvent> +#include <QtGui/QDropEvent> +#include <QtGui/QIcon> +#include <QtGui/QWindow> +#include <QtGui/QScreen> +#include <QtWidgets/QStyle> +#include <QtWidgets/QToolTip> +#include <QtWidgets/QApplication> +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) +#include <QtWidgets/QDesktopWidget> +#endif +#include <QtWidgets/QMenuBar> +#include <QtWidgets/QMainWindow> + +#if QT5_USING_X11 +#include <QtX11Extras/QX11Info> +#include <xcb/xproto.h> +#if QT5_HAVE_XCB_ICCCM +#include <xcb/xcb_icccm.h> +#endif +#endif + +#include <saldatabasic.hxx> +#include <window.h> +#include <vcl/syswin.hxx> + +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include <cairo.h> +#include <headless/svpgdi.hxx> + +#if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM +static bool g_bNeedsWmHintsWindowGroup = true; +static xcb_atom_t g_aXcbClientLeaderAtom = 0; +#endif + +static void SvpDamageHandler(void* handle, sal_Int32 nExtentsX, sal_Int32 nExtentsY, + sal_Int32 nExtentsWidth, sal_Int32 nExtentsHeight) +{ + QtFrame* pThis = static_cast<QtFrame*>(handle); + pThis->Damage(nExtentsX, nExtentsY, nExtentsWidth, nExtentsHeight); +} + +namespace +{ +sal_Int32 screenNumber(const QScreen* pScreen) +{ + const QList<QScreen*> screens = QApplication::screens(); + + sal_Int32 nScreen = 0; + bool bFound = false; + for (const QScreen* pCurScreen : screens) + { + if (pScreen == pCurScreen) + { + bFound = true; + break; + } + nScreen++; + } + + return bFound ? nScreen : -1; +} +} + +QtFrame::QtFrame(QtFrame* pParent, SalFrameStyleFlags nStyle, bool bUseCairo) + : m_pTopLevel(nullptr) + , m_bUseCairo(bUseCairo) + , m_bNullRegion(true) + , m_bGraphicsInUse(false) + , m_ePointerStyle(PointerStyle::Arrow) + , m_pDragSource(nullptr) + , m_pDropTarget(nullptr) + , m_bInDrag(false) + , m_bDefaultSize(true) + , m_bDefaultPos(true) + , m_bFullScreen(false) + , m_bFullScreenSpanAll(false) +#if QT5_USING_X11 + , m_nKeyModifiers(ModKeyFlags::NONE) +#endif + , m_nInputLanguage(LANGUAGE_DONTKNOW) +{ + QtInstance* pInst = static_cast<QtInstance*>(GetSalData()->m_pInstance); + pInst->insertFrame(this); + + m_aDamageHandler.handle = this; + m_aDamageHandler.damaged = ::SvpDamageHandler; + + if (nStyle & SalFrameStyleFlags::DEFAULT) // ensure default style + { + nStyle |= SalFrameStyleFlags::MOVEABLE | SalFrameStyleFlags::SIZEABLE + | SalFrameStyleFlags::CLOSEABLE; + nStyle &= ~SalFrameStyleFlags::FLOAT; + } + + m_nStyle = nStyle; + m_pParent = pParent; + + Qt::WindowFlags aWinFlags; + if (!(nStyle & SalFrameStyleFlags::SYSTEMCHILD)) + { + if (nStyle & SalFrameStyleFlags::INTRO) + aWinFlags |= Qt::SplashScreen; + // floating toolbars are frameless tool windows + // + they must be able to receive keyboard focus + else if ((nStyle & SalFrameStyleFlags::FLOAT) + && (nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)) + aWinFlags |= Qt::Tool | Qt::FramelessWindowHint; + else if (nStyle & SalFrameStyleFlags::TOOLTIP) + aWinFlags |= Qt::ToolTip; + // Can't use Qt::Popup, because it grabs the input focus and generates + // a focus-out event, reaching the combo box. This used to map to + // Qt::ToolTip, which doesn't feel that correct... + else if (isPopup()) + aWinFlags = Qt::Widget | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint; + else if (nStyle & SalFrameStyleFlags::TOOLWINDOW) + aWinFlags |= Qt::Tool; + // top level windows can't be transient in Qt, so make them dialogs, if they have a parent. At least + // the plasma shell relies on this setting to skip dialogs in the window list. And Qt Xcb will just + // set transient for the types Dialog, Sheet, Tool, SplashScreen, ToolTip, Drawer and Popup. + else if (nStyle & SalFrameStyleFlags::DIALOG || m_pParent) + aWinFlags |= Qt::Dialog; + else + aWinFlags |= Qt::Window; + } + + if (aWinFlags == Qt::Window) + { + m_pTopLevel = new QtMainWindow(*this, aWinFlags); + m_pQWidget = new QtWidget(*this, aWinFlags); + m_pTopLevel->setCentralWidget(m_pQWidget); + m_pTopLevel->setFocusProxy(m_pQWidget); + } + else + m_pQWidget = new QtWidget(*this, aWinFlags); + + if (pParent && !(pParent->m_nStyle & SalFrameStyleFlags::PLUG)) + { + QWindow* pParentWindow = pParent->GetQWidget()->window()->windowHandle(); + QWindow* pChildWindow = asChild()->window()->windowHandle(); + if (pParentWindow && pChildWindow && (pParentWindow != pChildWindow)) + pChildWindow->setTransientParent(pParentWindow); + } + + // Calling 'QWidget::winId()' implicitly enables native windows to be used + // rather than "alien widgets" that are unknown to the windowing system, + // s. https://doc.qt.io/qt-5/qwidget.html#native-widgets-vs-alien-widgets + // Avoid this on Wayland due to problems with missing 'mouseMoveEvent's, + // s. tdf#122293/QTBUG-75766 + const bool bWayland = QGuiApplication::platformName() == "wayland"; + if (!bWayland) + m_aSystemData.SetWindowHandle(m_pQWidget->winId()); + else + { + // TODO implement as needed for Wayland, + // s.a. commit c0d4f3ad3307c which did this for gtk3 + // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface(); + // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr); + // m_aSystemData.aWindow = reinterpret_cast<unsigned long>( + // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle())); + } + + m_aSystemData.aShellWindow = reinterpret_cast<sal_IntPtr>(this); + //m_aSystemData.pSalFrame = this; + m_aSystemData.pWidget = m_pQWidget; + //m_aSystemData.nScreen = m_nXScreen.getXScreen(); + m_aSystemData.toolkit = SystemEnvData::Toolkit::Qt5; + if (!bWayland) + m_aSystemData.platform = SystemEnvData::Platform::Xcb; + else + m_aSystemData.platform = SystemEnvData::Platform::Wayland; + + SetIcon(SV_ICON_ID_OFFICE); + + fixICCCMwindowGroup(); +} + +void QtFrame::fixICCCMwindowGroup() +{ +#if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM + // older Qt5 just sets WM_CLIENT_LEADER, but not the XCB_ICCCM_WM_HINT_WINDOW_GROUP + // see Qt commit 0de4b326d8 ("xcb: fix issue with dialogs hidden by other windows") + // or QTBUG-46626. So LO has to set this itself to help some WMs. + if (!g_bNeedsWmHintsWindowGroup) + return; + g_bNeedsWmHintsWindowGroup = false; + + if (QGuiApplication::platformName() != "xcb") + return; + if (QVersionNumber::fromString(qVersion()) >= QVersionNumber(5, 12)) + return; + + xcb_connection_t* conn = QX11Info::connection(); + xcb_window_t win = asChild()->winId(); + + xcb_icccm_wm_hints_t hints; + + xcb_get_property_cookie_t prop_cookie = xcb_icccm_get_wm_hints_unchecked(conn, win); + if (!xcb_icccm_get_wm_hints_reply(conn, prop_cookie, &hints, nullptr)) + return; + + if (hints.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP) + return; + + if (g_aXcbClientLeaderAtom == 0) + { + const char* const leader_name = "WM_CLIENT_LEADER\0"; + xcb_intern_atom_cookie_t atom_cookie + = xcb_intern_atom(conn, 1, strlen(leader_name), leader_name); + xcb_intern_atom_reply_t* atom_reply = xcb_intern_atom_reply(conn, atom_cookie, nullptr); + if (!atom_reply) + return; + g_aXcbClientLeaderAtom = atom_reply->atom; + free(atom_reply); + } + + g_bNeedsWmHintsWindowGroup = true; + + prop_cookie = xcb_get_property(conn, 0, win, g_aXcbClientLeaderAtom, XCB_ATOM_WINDOW, 0, 1); + xcb_get_property_reply_t* prop_reply = xcb_get_property_reply(conn, prop_cookie, nullptr); + if (!prop_reply) + return; + + if (xcb_get_property_value_length(prop_reply) != 4) + { + free(prop_reply); + return; + } + + xcb_window_t leader = *static_cast<xcb_window_t*>(xcb_get_property_value(prop_reply)); + free(prop_reply); + + hints.flags |= XCB_ICCCM_WM_HINT_WINDOW_GROUP; + hints.window_group = leader; + xcb_icccm_set_wm_hints(conn, win, &hints); +#else + (void)this; // avoid loplugin:staticmethods +#endif +} + +QtFrame::~QtFrame() +{ + QtInstance* pInst = static_cast<QtInstance*>(GetSalData()->m_pInstance); + pInst->eraseFrame(this); + delete asChild(); + m_aSystemData.aShellWindow = 0; +} + +void QtFrame::Damage(sal_Int32 nExtentsX, sal_Int32 nExtentsY, sal_Int32 nExtentsWidth, + sal_Int32 nExtentsHeight) const +{ + m_pQWidget->update(scaledQRect(QRect(nExtentsX, nExtentsY, nExtentsWidth, nExtentsHeight), + 1 / devicePixelRatioF())); +} + +SalGraphics* QtFrame::AcquireGraphics() +{ + if (m_bGraphicsInUse) + return nullptr; + + m_bGraphicsInUse = true; + + if (m_bUseCairo) + { + if (!m_pSvpGraphics) + { + QSize aSize = m_pQWidget->size() * devicePixelRatioF(); + m_pSvpGraphics.reset(new QtSvpGraphics(this)); + m_pSurface.reset( + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, aSize.width(), aSize.height())); + m_pSvpGraphics->setSurface(m_pSurface.get(), + basegfx::B2IVector(aSize.width(), aSize.height())); + cairo_surface_set_user_data(m_pSurface.get(), QtSvpGraphics::getDamageKey(), + &m_aDamageHandler, nullptr); + } + return m_pSvpGraphics.get(); + } + else + { + if (!m_pQtGraphics) + { + m_pQtGraphics.reset(new QtGraphics(this)); + m_pQImage.reset( + new QImage(m_pQWidget->size() * devicePixelRatioF(), Qt_DefaultFormat32)); + m_pQImage->fill(Qt::transparent); + m_pQtGraphics->ChangeQImage(m_pQImage.get()); + } + return m_pQtGraphics.get(); + } +} + +void QtFrame::ReleaseGraphics(SalGraphics* pSalGraph) +{ + (void)pSalGraph; + if (m_bUseCairo) + assert(pSalGraph == m_pSvpGraphics.get()); + else + assert(pSalGraph == m_pQtGraphics.get()); + m_bGraphicsInUse = false; +} + +bool QtFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData) +{ + QtInstance* pInst = static_cast<QtInstance*>(GetSalData()->m_pInstance); + pInst->PostEvent(this, pData.release(), SalEvent::UserEvent); + return true; +} + +QWidget* QtFrame::asChild() const { return m_pTopLevel ? m_pTopLevel : m_pQWidget; } + +qreal QtFrame::devicePixelRatioF() const { return asChild()->devicePixelRatioF(); } + +bool QtFrame::isWindow() const { return asChild()->isWindow(); } + +QWindow* QtFrame::windowHandle() const +{ + // set attribute 'Qt::WA_NativeWindow' first to make sure a window handle actually exists + QWidget* pChild = asChild(); + pChild->setAttribute(Qt::WA_NativeWindow); + return pChild->windowHandle(); +} + +QScreen* QtFrame::screen() const +{ + QWindow* const pWindow = windowHandle(); + return pWindow ? pWindow->screen() : nullptr; +} + +bool QtFrame::isMinimized() const { return asChild()->isMinimized(); } + +bool QtFrame::isMaximized() const { return asChild()->isMaximized(); } + +void QtFrame::SetWindowStateImpl(Qt::WindowStates eState) +{ + return asChild()->setWindowState(eState); +} + +void QtFrame::SetTitle(const OUString& rTitle) +{ + m_pQWidget->window()->setWindowTitle(toQString(rTitle)); +} + +void QtFrame::SetIcon(sal_uInt16 nIcon) +{ + if (m_nStyle + & (SalFrameStyleFlags::PLUG | SalFrameStyleFlags::SYSTEMCHILD + | SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::INTRO + | SalFrameStyleFlags::OWNERDRAWDECORATION) + || !isWindow()) + return; + + QString appicon; + + if (nIcon == SV_ICON_ID_TEXT) + appicon = "libreoffice-writer"; + else if (nIcon == SV_ICON_ID_SPREADSHEET) + appicon = "libreoffice-calc"; + else if (nIcon == SV_ICON_ID_DRAWING) + appicon = "libreoffice-draw"; + else if (nIcon == SV_ICON_ID_PRESENTATION) + appicon = "libreoffice-impress"; + else if (nIcon == SV_ICON_ID_DATABASE) + appicon = "libreoffice-base"; + else if (nIcon == SV_ICON_ID_FORMULA) + appicon = "libreoffice-math"; + else + appicon = "libreoffice-startcenter"; + + QIcon aIcon = QIcon::fromTheme(appicon); + m_pQWidget->window()->setWindowIcon(aIcon); +} + +void QtFrame::SetMenu(SalMenu*) {} + +void QtFrame::DrawMenuBar() { /* not needed */} + +void QtFrame::SetExtendedFrameStyle(SalExtStyle /*nExtStyle*/) { /* not needed */} + +void QtFrame::Show(bool bVisible, bool bNoActivate) +{ + assert(m_pQWidget); + if (bVisible == asChild()->isVisible()) + return; + + SetDefaultSize(); + SetDefaultPos(); + + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, bVisible, bNoActivate]() { + asChild()->setVisible(bVisible); + asChild()->raise(); + if (!bNoActivate && !isPopup()) + { + asChild()->activateWindow(); + asChild()->setFocus(); + } + }); +} + +void QtFrame::SetMinClientSize(tools::Long nWidth, tools::Long nHeight) +{ + if (!isChild()) + { + const qreal fRatio = devicePixelRatioF(); + asChild()->setMinimumSize(round(nWidth / fRatio), round(nHeight / fRatio)); + } +} + +void QtFrame::SetMaxClientSize(tools::Long nWidth, tools::Long nHeight) +{ + if (!isChild()) + { + const qreal fRatio = devicePixelRatioF(); + asChild()->setMaximumSize(round(nWidth / fRatio), round(nHeight / fRatio)); + } +} + +void QtFrame::SetDefaultPos() +{ + if (!m_bDefaultPos) + return; + + // center on parent + if (m_pParent) + { + const qreal fRatio = devicePixelRatioF(); + QWidget* const pWindow = m_pParent->GetQWidget()->window(); + QWidget* const pWidget = asChild(); + QPoint aPos = pWindow->rect().center() - pWidget->rect().center(); + SetPosSize(round(aPos.x() * fRatio), round(aPos.y() * fRatio), 0, 0, + SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y); + assert(!m_bDefaultPos); + } + else + m_bDefaultPos = false; +} + +Size QtFrame::CalcDefaultSize() +{ + assert(isWindow()); + + Size aSize; + if (!m_bFullScreen) + { + const QScreen* pScreen = screen(); + if (!pScreen) + pScreen = QGuiApplication::screens().at(0); + aSize = bestmaxFrameSizeForScreenSize(toSize(pScreen->size())); + } + else + { + if (!m_bFullScreenSpanAll) + { + aSize = toSize(QGuiApplication::screens().at(maGeometry.nDisplayScreenNumber)->size()); + } + else + { +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + QScreen* pScreen = QGuiApplication::screenAt(QPoint(0, 0)); +#else + // QGuiApplication::screenAt was added in Qt 5.10, use deprecated QDesktopWidget + int nLeftScreen = QApplication::desktop()->screenNumber(QPoint(0, 0)); + QScreen* pScreen = QGuiApplication::screens()[nLeftScreen]; +#endif + aSize = toSize(pScreen->availableVirtualGeometry().size()); + } + } + + return aSize; +} + +void QtFrame::SetDefaultSize() +{ + if (!m_bDefaultSize) + return; + + Size aDefSize = CalcDefaultSize(); + SetPosSize(0, 0, aDefSize.Width(), aDefSize.Height(), + SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT); + assert(!m_bDefaultSize); +} + +void QtFrame::SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + sal_uInt16 nFlags) +{ + if (!isWindow() || isChild(true, false)) + return; + + if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) + { + if (isChild(false) || !m_pQWidget->isMaximized()) + { + if (!(nFlags & SAL_FRAME_POSSIZE_WIDTH)) + nWidth = maGeometry.nWidth; + else if (!(nFlags & SAL_FRAME_POSSIZE_HEIGHT)) + nHeight = maGeometry.nHeight; + + if (nWidth > 0 && nHeight > 0) + { + m_bDefaultSize = false; + const int nNewWidth = round(nWidth / devicePixelRatioF()); + const int nNewHeight = round(nHeight / devicePixelRatioF()); + if (m_nStyle & SalFrameStyleFlags::SIZEABLE) + asChild()->resize(nNewWidth, nNewHeight); + else + asChild()->setFixedSize(nNewWidth, nNewHeight); + } + + // assume the resize happened + // needed for calculations and will eventually be corrected by events + if (nWidth > 0) + maGeometry.nWidth = nWidth; + if (nHeight > 0) + maGeometry.nHeight = nHeight; + } + } + + if (!(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))) + return; + + if (m_pParent) + { + const SalFrameGeometry& aParentGeometry = m_pParent->maGeometry; + if (QGuiApplication::isRightToLeft()) + nX = aParentGeometry.nX + aParentGeometry.nWidth - nX - maGeometry.nWidth - 1; + else + nX += aParentGeometry.nX; + nY += aParentGeometry.nY; + + QtMainWindow* pTopLevel = m_pParent->GetTopLevelWindow(); + if (pTopLevel && pTopLevel->menuBar() && pTopLevel->menuBar()->isVisible()) + nY += round(pTopLevel->menuBar()->geometry().height() * devicePixelRatioF()); + } + + if (!(nFlags & SAL_FRAME_POSSIZE_X)) + nX = maGeometry.nX; + else if (!(nFlags & SAL_FRAME_POSSIZE_Y)) + nY = maGeometry.nY; + + // assume the reposition happened + // needed for calculations and will eventually be corrected by events later + maGeometry.nX = nX; + maGeometry.nY = nY; + + m_bDefaultPos = false; + asChild()->move(round(nX / devicePixelRatioF()), round(nY / devicePixelRatioF())); +} + +void QtFrame::GetClientSize(tools::Long& rWidth, tools::Long& rHeight) +{ + rWidth = round(m_pQWidget->width() * devicePixelRatioF()); + rHeight = round(m_pQWidget->height() * devicePixelRatioF()); +} + +void QtFrame::GetWorkArea(tools::Rectangle& rRect) +{ + if (!isWindow()) + return; + QScreen* pScreen = screen(); + if (!pScreen) + return; + + QSize aSize = pScreen->availableVirtualSize() * devicePixelRatioF(); + rRect = tools::Rectangle(0, 0, aSize.width(), aSize.height()); +} + +SalFrame* QtFrame::GetParent() const { return m_pParent; } + +void QtFrame::SetModal(bool bModal) +{ + if (!isWindow()) + return; + + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, bModal]() { + + QWidget* const pChild = asChild(); + const bool bWasVisible = pChild->isVisible(); + + // modality change is only effective if the window is hidden + if (bWasVisible) + pChild->hide(); + + pChild->setWindowModality(bModal ? Qt::WindowModal : Qt::NonModal); + + if (bWasVisible) + pChild->show(); + }); +} + +bool QtFrame::GetModal() const { return isWindow() && windowHandle()->isModal(); } + +void QtFrame::SetWindowState(const SalFrameState* pState) +{ + if (!isWindow() || !pState || isChild(true, false)) + return; + + const WindowStateMask nMaxGeometryMask + = WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width | WindowStateMask::Height + | WindowStateMask::MaximizedX | WindowStateMask::MaximizedY + | WindowStateMask::MaximizedWidth | WindowStateMask::MaximizedHeight; + + if ((pState->mnMask & WindowStateMask::State) && (pState->mnState & WindowStateState::Maximized) + && !isMaximized() && (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask) + { + const qreal fRatio = devicePixelRatioF(); + QWidget* const pChild = asChild(); + pChild->resize(ceil(pState->mnWidth / fRatio), ceil(pState->mnHeight / fRatio)); + pChild->move(ceil(pState->mnX / fRatio), ceil(pState->mnY / fRatio)); + SetWindowStateImpl(Qt::WindowMaximized); + } + else if (pState->mnMask + & (WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width + | WindowStateMask::Height)) + { + sal_uInt16 nPosSizeFlags = 0; + if (pState->mnMask & WindowStateMask::X) + nPosSizeFlags |= SAL_FRAME_POSSIZE_X; + if (pState->mnMask & WindowStateMask::Y) + nPosSizeFlags |= SAL_FRAME_POSSIZE_Y; + if (pState->mnMask & WindowStateMask::Width) + nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH; + if (pState->mnMask & WindowStateMask::Height) + nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT; + SetPosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nPosSizeFlags); + } + else if (pState->mnMask & WindowStateMask::State && !isChild()) + { + if (pState->mnState & WindowStateState::Maximized) + SetWindowStateImpl(Qt::WindowMaximized); + else if (pState->mnState & WindowStateState::Minimized) + SetWindowStateImpl(Qt::WindowMinimized); + else + SetWindowStateImpl(Qt::WindowNoState); + } +} + +bool QtFrame::GetWindowState(SalFrameState* pState) +{ + pState->mnState = WindowStateState::Normal; + pState->mnMask = WindowStateMask::State; + if (isMinimized() /*|| !windowHandle()*/) + pState->mnState |= WindowStateState::Minimized; + else if (isMaximized()) + { + pState->mnState |= WindowStateState::Maximized; + } + else + { + // geometry() is the drawable area, which is wanted here + QRect rect = scaledQRect(asChild()->geometry(), devicePixelRatioF()); + pState->mnX = rect.x(); + pState->mnY = rect.y(); + pState->mnWidth = rect.width(); + pState->mnHeight = rect.height(); + pState->mnMask |= WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width + | WindowStateMask::Height; + } + + return true; +} + +void QtFrame::ShowFullScreen(bool bFullScreen, sal_Int32 nScreen) +{ + // only top-level windows can go fullscreen + assert(m_pTopLevel); + + if (m_bFullScreen == bFullScreen) + return; + + m_bFullScreen = bFullScreen; + m_bFullScreenSpanAll = m_bFullScreen && (nScreen < 0); + + // show it if it isn't shown yet + if (!isWindow()) + m_pTopLevel->show(); + + if (m_bFullScreen) + { + m_aRestoreGeometry = m_pTopLevel->geometry(); + m_nRestoreScreen = maGeometry.nDisplayScreenNumber; + SetScreenNumber(m_bFullScreenSpanAll ? m_nRestoreScreen : nScreen); + if (!m_bFullScreenSpanAll) + windowHandle()->showFullScreen(); + else + windowHandle()->showNormal(); + } + else + { + SetScreenNumber(m_nRestoreScreen); + windowHandle()->showNormal(); + m_pTopLevel->setGeometry(m_aRestoreGeometry); + } +} + +void QtFrame::StartPresentation(bool bStart) +{ +// meh - so there's no Qt platform independent solution +// https://forum.qt.io/topic/38504/solved-qdialog-in-fullscreen-disable-os-screensaver +#if QT5_USING_X11 + std::optional<unsigned int> aRootWindow; + std::optional<Display*> aDisplay; + + if (QX11Info::isPlatformX11()) + { + aRootWindow = QX11Info::appRootWindow(); + aDisplay = QX11Info::display(); + } + + m_ScreenSaverInhibitor.inhibit(bStart, u"presentation", QX11Info::isPlatformX11(), aRootWindow, + aDisplay); +#else + (void)bStart; +#endif +} + +void QtFrame::SetAlwaysOnTop(bool bOnTop) +{ + QWidget* const pWidget = asChild(); + const Qt::WindowFlags flags = pWidget->windowFlags(); + if (bOnTop) + pWidget->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); + else + pWidget->setWindowFlags(flags & ~(Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint)); +} + +void QtFrame::ToTop(SalFrameToTop nFlags) +{ + QWidget* const pWidget = asChild(); + if (isWindow() && !(nFlags & SalFrameToTop::GrabFocusOnly)) + pWidget->raise(); + if ((nFlags & SalFrameToTop::RestoreWhenMin) || (nFlags & SalFrameToTop::ForegroundTask)) + pWidget->activateWindow(); + else if ((nFlags & SalFrameToTop::GrabFocus) || (nFlags & SalFrameToTop::GrabFocusOnly)) + { + pWidget->activateWindow(); + pWidget->setFocus(); + } +} + +void QtFrame::SetPointer(PointerStyle ePointerStyle) +{ + QWindow* pWindow = m_pQWidget->window()->windowHandle(); + if (!pWindow) + return; + if (ePointerStyle == m_ePointerStyle) + return; + m_ePointerStyle = ePointerStyle; + + pWindow->setCursor(static_cast<QtData*>(GetSalData())->getCursor(ePointerStyle)); +} + +void QtFrame::CaptureMouse(bool bMouse) +{ + static const char* pEnv = getenv("SAL_NO_MOUSEGRABS"); + if (pEnv && *pEnv) + return; + + if (bMouse) + m_pQWidget->grabMouse(); + else + m_pQWidget->releaseMouse(); +} + +void QtFrame::SetPointerPos(tools::Long nX, tools::Long nY) +{ + // some cursor already exists (and it has m_ePointerStyle shape) + // so here we just reposition it + QCursor::setPos(m_pQWidget->mapToGlobal(QPoint(nX, nY))); +} + +void QtFrame::Flush() +{ + // was: QGuiApplication::sync(); + // but FIXME it causes too many issues, figure out sth better + + // unclear if we need to also flush cairo surface - gtk3 backend + // does not do it. QPainter in QtWidget::paintEvent() is + // destroyed, so that state should be safely flushed. +} + +bool QtFrame::ShowTooltip(const OUString& rText, const tools::Rectangle& rHelpArea) +{ + QRect aHelpArea(toQRect(rHelpArea)); + if (QGuiApplication::isRightToLeft()) + aHelpArea.moveLeft(maGeometry.nWidth - aHelpArea.width() - aHelpArea.left() - 1); + QToolTip::showText(QCursor::pos(), toQString(rText), m_pQWidget, aHelpArea); + return true; +} + +void QtFrame::SetInputContext(SalInputContext* pContext) +{ + if (!pContext) + return; + + if (!(pContext->mnOptions & InputContextFlags::Text)) + return; + + m_pQWidget->setAttribute(Qt::WA_InputMethodEnabled); +} + +void QtFrame::EndExtTextInput(EndExtTextInputFlags /*nFlags*/) +{ + QtWidget* pQtWidget = static_cast<QtWidget*>(m_pQWidget); + if (pQtWidget) + pQtWidget->endExtTextInput(); +} + +OUString QtFrame::GetKeyName(sal_uInt16 nKeyCode) +{ + vcl::KeyCode vclKeyCode(nKeyCode); + int nCode = vclKeyCode.GetCode(); + int nRetCode = 0; + + if (nCode >= KEY_0 && nCode <= KEY_9) + nRetCode = (nCode - KEY_0) + Qt::Key_0; + else if (nCode >= KEY_A && nCode <= KEY_Z) + nRetCode = (nCode - KEY_A) + Qt::Key_A; + else if (nCode >= KEY_F1 && nCode <= KEY_F26) + nRetCode = (nCode - KEY_F1) + Qt::Key_F1; + else + { + switch (nCode) + { + case KEY_DOWN: + nRetCode = Qt::Key_Down; + break; + case KEY_UP: + nRetCode = Qt::Key_Up; + break; + case KEY_LEFT: + nRetCode = Qt::Key_Left; + break; + case KEY_RIGHT: + nRetCode = Qt::Key_Right; + break; + case KEY_HOME: + nRetCode = Qt::Key_Home; + break; + case KEY_END: + nRetCode = Qt::Key_End; + break; + case KEY_PAGEUP: + nRetCode = Qt::Key_PageUp; + break; + case KEY_PAGEDOWN: + nRetCode = Qt::Key_PageDown; + break; + case KEY_RETURN: + nRetCode = Qt::Key_Return; + break; + case KEY_ESCAPE: + nRetCode = Qt::Key_Escape; + break; + case KEY_TAB: + nRetCode = Qt::Key_Tab; + break; + case KEY_BACKSPACE: + nRetCode = Qt::Key_Backspace; + break; + case KEY_SPACE: + nRetCode = Qt::Key_Space; + break; + case KEY_INSERT: + nRetCode = Qt::Key_Insert; + break; + case KEY_DELETE: + nRetCode = Qt::Key_Delete; + break; + case KEY_ADD: + nRetCode = Qt::Key_Plus; + break; + case KEY_SUBTRACT: + nRetCode = Qt::Key_Minus; + break; + case KEY_MULTIPLY: + nRetCode = Qt::Key_Asterisk; + break; + case KEY_DIVIDE: + nRetCode = Qt::Key_Slash; + break; + case KEY_POINT: + nRetCode = Qt::Key_Period; + break; + case KEY_COMMA: + nRetCode = Qt::Key_Comma; + break; + case KEY_LESS: + nRetCode = Qt::Key_Less; + break; + case KEY_GREATER: + nRetCode = Qt::Key_Greater; + break; + case KEY_EQUAL: + nRetCode = Qt::Key_Equal; + break; + case KEY_FIND: + nRetCode = Qt::Key_Find; + break; + case KEY_CONTEXTMENU: + nRetCode = Qt::Key_Menu; + break; + case KEY_HELP: + nRetCode = Qt::Key_Help; + break; + case KEY_UNDO: + nRetCode = Qt::Key_Undo; + break; + case KEY_REPEAT: + nRetCode = Qt::Key_Redo; + break; + case KEY_TILDE: + nRetCode = Qt::Key_AsciiTilde; + break; + case KEY_QUOTELEFT: + nRetCode = Qt::Key_QuoteLeft; + break; + case KEY_BRACKETLEFT: + nRetCode = Qt::Key_BracketLeft; + break; + case KEY_BRACKETRIGHT: + nRetCode = Qt::Key_BracketRight; + break; + case KEY_SEMICOLON: + nRetCode = Qt::Key_Semicolon; + break; + + // Special cases + case KEY_COPY: + nRetCode = Qt::Key_Copy; + break; + case KEY_CUT: + nRetCode = Qt::Key_Cut; + break; + case KEY_PASTE: + nRetCode = Qt::Key_Paste; + break; + case KEY_OPEN: + nRetCode = Qt::Key_Open; + break; + } + } + + if (vclKeyCode.IsShift()) + nRetCode += Qt::SHIFT; + if (vclKeyCode.IsMod1()) + nRetCode += Qt::CTRL; + if (vclKeyCode.IsMod2()) + nRetCode += Qt::ALT; + + QKeySequence keySeq(nRetCode); + OUString sKeyName = toOUString(keySeq.toString()); + + return sKeyName; +} + +bool QtFrame::MapUnicodeToKeyCode(sal_Unicode /*aUnicode*/, LanguageType /*aLangType*/, + vcl::KeyCode& /*rKeyCode*/) +{ + // not supported yet + return false; +} + +LanguageType QtFrame::GetInputLanguage() { return m_nInputLanguage; } + +void QtFrame::setInputLanguage(LanguageType nInputLanguage) +{ + if (nInputLanguage == m_nInputLanguage) + return; + m_nInputLanguage = nInputLanguage; + CallCallback(SalEvent::InputLanguageChange, nullptr); +} + +static Color toColor(const QColor& rColor) +{ + return Color(rColor.red(), rColor.green(), rColor.blue()); +} + +void QtFrame::UpdateSettings(AllSettings& rSettings) +{ + if (QtData::noNativeControls()) + return; + + StyleSettings style(rSettings.GetStyleSettings()); + + // General settings + QPalette pal = QApplication::palette(); + + style.SetToolbarIconSize(ToolbarIconSize::Large); + + Color aFore = toColor(pal.color(QPalette::Active, QPalette::WindowText)); + Color aBack = toColor(pal.color(QPalette::Active, QPalette::Window)); + Color aText = toColor(pal.color(QPalette::Active, QPalette::Text)); + Color aBase = toColor(pal.color(QPalette::Active, QPalette::Base)); + Color aButn = toColor(pal.color(QPalette::Active, QPalette::ButtonText)); + Color aMid = toColor(pal.color(QPalette::Active, QPalette::Mid)); + Color aHigh = toColor(pal.color(QPalette::Active, QPalette::Highlight)); + Color aHighText = toColor(pal.color(QPalette::Active, QPalette::HighlightedText)); + Color aLink = toColor(pal.color(QPalette::Active, QPalette::Link)); + Color aVisitedLink = toColor(pal.color(QPalette::Active, QPalette::LinkVisited)); + + style.SetSkipDisabledInMenus(true); + + // Foreground + style.SetRadioCheckTextColor(aFore); + style.SetLabelTextColor(aFore); + style.SetDialogTextColor(aFore); + style.SetGroupTextColor(aFore); + + // Text + style.SetFieldTextColor(aText); + style.SetFieldRolloverTextColor(aText); + style.SetWindowTextColor(aText); + style.SetToolTextColor(aText); + + // Base + style.SetFieldColor(aBase); + style.SetWindowColor(aBase); + style.SetActiveTabColor(aBase); + style.SetAlternatingRowColor(toColor(pal.color(QPalette::Active, QPalette::AlternateBase))); + + // Buttons + style.SetDefaultButtonTextColor(aButn); + style.SetButtonTextColor(aButn); + style.SetDefaultActionButtonTextColor(aButn); + style.SetActionButtonTextColor(aButn); + style.SetFlatButtonTextColor(aButn); + style.SetDefaultButtonRolloverTextColor(aButn); + style.SetButtonRolloverTextColor(aButn); + style.SetDefaultActionButtonRolloverTextColor(aButn); + style.SetActionButtonRolloverTextColor(aButn); + style.SetFlatButtonRolloverTextColor(aButn); + style.SetDefaultButtonPressedRolloverTextColor(aButn); + style.SetButtonPressedRolloverTextColor(aButn); + style.SetDefaultActionButtonPressedRolloverTextColor(aButn); + style.SetActionButtonPressedRolloverTextColor(aButn); + style.SetFlatButtonPressedRolloverTextColor(aButn); + + // Tabs + style.SetTabTextColor(aButn); + style.SetTabRolloverTextColor(aButn); + style.SetTabHighlightTextColor(aButn); + + // Disable color + style.SetDisableColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText))); + + // Background + style.BatchSetBackgrounds(aBack); + style.SetInactiveTabColor(aBack); + + // Workspace + style.SetWorkspaceColor(aMid); + + // Selection + style.SetHighlightColor(aHigh); + style.SetHighlightTextColor(aHighText); + style.SetActiveColor(aHigh); + style.SetActiveTextColor(aHighText); + + // Links + style.SetLinkColor(aLink); + style.SetVisitedLinkColor(aVisitedLink); + + // Tooltip + style.SetHelpColor(toColor(QToolTip::palette().color(QPalette::Active, QPalette::ToolTipBase))); + style.SetHelpTextColor( + toColor(QToolTip::palette().color(QPalette::Active, QPalette::ToolTipText))); + + const int flash_time = QApplication::cursorFlashTime(); + style.SetCursorBlinkTime(flash_time != 0 ? flash_time / 2 : STYLE_CURSOR_NOBLINKTIME); + + // Menu + std::unique_ptr<QMenuBar> pMenuBar = std::make_unique<QMenuBar>(); + QPalette qMenuCG = pMenuBar->palette(); + + // Menu text and background color, theme specific + Color aMenuFore = toColor(qMenuCG.color(QPalette::WindowText)); + Color aMenuBack = toColor(qMenuCG.color(QPalette::Window)); + + style.SetMenuTextColor(aMenuFore); + style.SetMenuBarTextColor(style.GetPersonaMenuBarTextColor().value_or(aMenuFore)); + style.SetMenuColor(aMenuBack); + style.SetMenuBarColor(aMenuBack); + style.SetMenuHighlightColor(toColor(qMenuCG.color(QPalette::Highlight))); + style.SetMenuHighlightTextColor(toColor(qMenuCG.color(QPalette::HighlightedText))); + + // set special menubar highlight text color + if (QApplication::style()->inherits("HighContrastStyle")) + ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor + = toColor(qMenuCG.color(QPalette::HighlightedText)); + else + ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore; + + // set menubar rollover color + if (pMenuBar->style()->styleHint(QStyle::SH_MenuBar_MouseTracking)) + { + style.SetMenuBarRolloverColor(toColor(qMenuCG.color(QPalette::Highlight))); + style.SetMenuBarRolloverTextColor(ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor); + } + else + { + style.SetMenuBarRolloverColor(aMenuBack); + style.SetMenuBarRolloverTextColor(aMenuFore); + } + style.SetMenuBarHighlightTextColor(style.GetMenuHighlightTextColor()); + + // Icon theme + style.SetPreferredIconTheme(toOUString(QIcon::themeName())); + + // Scroll bar size + style.SetScrollBarSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent)); + style.SetMinThumbSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarSliderMin)); + + // These colors are used for the ruler text and marks + style.SetShadowColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText))); + style.SetDarkShadowColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText))); + + rSettings.SetStyleSettings(style); +} + +void QtFrame::Beep() { QApplication::beep(); } + +SalFrame::SalPointerState QtFrame::GetPointerState() +{ + SalPointerState aState; + aState.maPos = toPoint(QCursor::pos() * devicePixelRatioF()); + aState.maPos.Move(-maGeometry.nX, -maGeometry.nY); + aState.mnState = GetMouseModCode(QGuiApplication::mouseButtons()) + | GetKeyModCode(QGuiApplication::keyboardModifiers()); + return aState; +} + +KeyIndicatorState QtFrame::GetIndicatorState() { return KeyIndicatorState(); } + +void QtFrame::SimulateKeyPress(sal_uInt16 nKeyCode) +{ + SAL_WARN("vcl.qt5", "missing simulate keypress " << nKeyCode); +} + +void QtFrame::SetParent(SalFrame* pNewParent) { m_pParent = static_cast<QtFrame*>(pNewParent); } + +void QtFrame::SetPluginParent(SystemParentData* /*pNewParent*/) +{ + //FIXME: no SetPluginParent impl. for qt5 +} + +void QtFrame::ResetClipRegion() { m_bNullRegion = true; } + +void QtFrame::BeginSetClipRegion(sal_uInt32) +{ + m_aRegion = QRegion(QRect(QPoint(0, 0), m_pQWidget->size())); +} + +void QtFrame::UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) +{ + m_aRegion + = m_aRegion.united(scaledQRect(QRect(nX, nY, nWidth, nHeight), 1 / devicePixelRatioF())); +} + +void QtFrame::EndSetClipRegion() { m_bNullRegion = false; } + +void QtFrame::SetScreenNumber(unsigned int nScreen) +{ + if (!isWindow()) + return; + + QWindow* const pWindow = windowHandle(); + if (!pWindow) + return; + + QList<QScreen*> screens = QApplication::screens(); + if (static_cast<int>(nScreen) < screens.size() || m_bFullScreenSpanAll) + { + QRect screenGeo; + + if (!m_bFullScreenSpanAll) + { + screenGeo = QGuiApplication::screens().at(nScreen)->geometry(); + pWindow->setScreen(QApplication::screens()[nScreen]); + } + else // special case: fullscreen over all available screens + { + assert(m_bFullScreen); + // left-most screen +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + QScreen* pScreen = QGuiApplication::screenAt(QPoint(0, 0)); +#else + // QGuiApplication::screenAt was added in Qt 5.10, use deprecated QDesktopWidget + int nLeftScreen = QApplication::desktop()->screenNumber(QPoint(0, 0)); + QScreen* pScreen = QGuiApplication::screens()[nLeftScreen]; +#endif + // entire virtual desktop + screenGeo = pScreen->availableVirtualGeometry(); + pWindow->setScreen(pScreen); + pWindow->setGeometry(screenGeo); + nScreen = screenNumber(pScreen); + } + + // setScreen by itself has no effect, explicitly move the widget to + // the new screen + asChild()->move(screenGeo.topLeft()); + } + else + { + // index outta bounds, use primary screen + QScreen* primaryScreen = QApplication::primaryScreen(); + pWindow->setScreen(primaryScreen); + nScreen = static_cast<sal_uInt32>(screenNumber(primaryScreen)); + } + + maGeometry.nDisplayScreenNumber = nScreen; +} + +void QtFrame::SetApplicationID(const OUString& rWMClass) +{ +#if QT5_USING_X11 + if (QGuiApplication::platformName() != "xcb" || !m_pTopLevel) + return; + + OString aResClass = OUStringToOString(rWMClass, RTL_TEXTENCODING_ASCII_US); + const char* pResClass + = !aResClass.isEmpty() ? aResClass.getStr() : SalGenericSystem::getFrameClassName(); + OString aResName = SalGenericSystem::getFrameResName(); + + // the WM_CLASS data consists of two concatenated cstrings, including the terminating '\0' chars + const uint32_t data_len = aResName.getLength() + 1 + strlen(pResClass) + 1; + char* data = new char[data_len]; + memcpy(data, aResName.getStr(), aResName.getLength() + 1); + memcpy(data + aResName.getLength() + 1, pResClass, strlen(pResClass) + 1); + + xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, m_pTopLevel->winId(), + XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, data_len, data); + delete[] data; +#else + (void)rWMClass; +#endif +} + +// Drag'n'drop foo + +void QtFrame::registerDragSource(QtDragSource* pDragSource) +{ + assert(!m_pDragSource); + m_pDragSource = pDragSource; +} + +void QtFrame::deregisterDragSource(QtDragSource const* pDragSource) +{ + assert(m_pDragSource == pDragSource); + (void)pDragSource; + m_pDragSource = nullptr; +} + +void QtFrame::registerDropTarget(QtDropTarget* pDropTarget) +{ + assert(!m_pDropTarget); + m_pDropTarget = pDropTarget; + m_pQWidget->setAcceptDrops(true); +} + +void QtFrame::deregisterDropTarget(QtDropTarget const* pDropTarget) +{ + assert(m_pDropTarget == pDropTarget); + (void)pDropTarget; + m_pDropTarget = nullptr; +} + +static css::uno::Reference<css::datatransfer::XTransferable> +lcl_getXTransferable(const QMimeData* pMimeData) +{ + css::uno::Reference<css::datatransfer::XTransferable> xTransferable; + const QtMimeData* pQtMimeData = dynamic_cast<const QtMimeData*>(pMimeData); + if (!pQtMimeData) + xTransferable = new QtDnDTransferable(pMimeData); + else + xTransferable = pQtMimeData->xTransferable(); + return xTransferable; +} + +static sal_Int8 lcl_getUserDropAction(const QDropEvent* pEvent, const sal_Int8 nSourceActions, + const QMimeData* pMimeData) +{ + // we completely ignore all proposals by the Qt event, as they don't + // match at all with the preferred LO DnD actions. + + // check the key modifiers to detect a user-overridden DnD action + const Qt::KeyboardModifiers eKeyMod = pEvent->keyboardModifiers(); + sal_Int8 nUserDropAction = 0; + if ((eKeyMod & Qt::ShiftModifier) && !(eKeyMod & Qt::ControlModifier)) + nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_MOVE; + else if ((eKeyMod & Qt::ControlModifier) && !(eKeyMod & Qt::ShiftModifier)) + nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_COPY; + else if ((eKeyMod & Qt::ShiftModifier) && (eKeyMod & Qt::ControlModifier)) + nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_LINK; + nUserDropAction &= nSourceActions; + + // select the default DnD action, if there isn't a user preference + if (0 == nUserDropAction) + { + // default LO internal action is move, but default external action is copy + nUserDropAction = dynamic_cast<const QtMimeData*>(pMimeData) + ? css::datatransfer::dnd::DNDConstants::ACTION_MOVE + : css::datatransfer::dnd::DNDConstants::ACTION_COPY; + nUserDropAction &= nSourceActions; + + // if the default doesn't match any allowed source action, fall back to the + // preferred of all allowed source actions + if (0 == nUserDropAction) + nUserDropAction = toVclDropAction(getPreferredDropAction(nSourceActions)); + + // this is "our" preference, but actually we would even prefer any default, + // if there is any + nUserDropAction |= css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT; + } + return nUserDropAction; +} + +void QtFrame::handleDragMove(QDragMoveEvent* pEvent) +{ + assert(m_pDropTarget); + + // prepare our suggested drop action for the drop target + const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions()); + const QMimeData* pMimeData = pEvent->mimeData(); + const sal_Int8 nUserDropAction = lcl_getUserDropAction(pEvent, nSourceActions, pMimeData); + const Point aPos = toPoint(pEvent->pos() * devicePixelRatioF()); + + css::datatransfer::dnd::DropTargetDragEnterEvent aEvent; + aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget); + aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDragContext*>(m_pDropTarget); + aEvent.LocationX = aPos.X(); + aEvent.LocationY = aPos.Y(); + aEvent.DropAction = nUserDropAction; + aEvent.SourceActions = nSourceActions; + + // ask the drop target to accept our drop action + if (!m_bInDrag) + { + aEvent.SupportedDataFlavors = lcl_getXTransferable(pMimeData)->getTransferDataFlavors(); + m_pDropTarget->fire_dragEnter(aEvent); + m_bInDrag = true; + } + else + m_pDropTarget->fire_dragOver(aEvent); + + // the drop target accepted our drop action => inform Qt + if (m_pDropTarget->proposedDropAction() != 0) + { + pEvent->setDropAction(getPreferredDropAction(m_pDropTarget->proposedDropAction())); + pEvent->accept(); + } + else // or maybe someone else likes it? + pEvent->ignore(); +} + +void QtFrame::handleDrop(QDropEvent* pEvent) +{ + assert(m_pDropTarget); + + // prepare our suggested drop action for the drop target + const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions()); + const sal_Int8 nUserDropAction + = lcl_getUserDropAction(pEvent, nSourceActions, pEvent->mimeData()); + const Point aPos = toPoint(pEvent->pos() * devicePixelRatioF()); + + css::datatransfer::dnd::DropTargetDropEvent aEvent; + aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget); + aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDropContext*>(m_pDropTarget); + aEvent.LocationX = aPos.X(); + aEvent.LocationY = aPos.Y(); + aEvent.SourceActions = nSourceActions; + aEvent.DropAction = nUserDropAction; + aEvent.Transferable = lcl_getXTransferable(pEvent->mimeData()); + + // ask the drop target to accept our drop action + m_pDropTarget->fire_drop(aEvent); + m_bInDrag = false; + + const bool bDropSuccessful = m_pDropTarget->dropSuccessful(); + const sal_Int8 nDropAction = m_pDropTarget->proposedDropAction(); + + // inform the drag source of the drag-origin frame of the drop result + if (pEvent->source()) + { + QtWidget* pWidget = dynamic_cast<QtWidget*>(pEvent->source()); + assert(pWidget); // AFAIK there shouldn't be any non-Qt5Widget as source in LO itself + if (pWidget) + pWidget->frame().m_pDragSource->fire_dragEnd(nDropAction, bDropSuccessful); + } + + // the drop target accepted our drop action => inform Qt + if (bDropSuccessful) + { + pEvent->setDropAction(getPreferredDropAction(nDropAction)); + pEvent->accept(); + } + else // or maybe someone else likes it? + pEvent->ignore(); +} + +void QtFrame::handleDragLeave() +{ + css::datatransfer::dnd::DropTargetEvent aEvent; + aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget); + m_pDropTarget->fire_dragExit(aEvent); + m_bInDrag = false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtGraphics.cxx b/vcl/qt5/QtGraphics.cxx new file mode 100644 index 000000000000..d809556ce219 --- /dev/null +++ b/vcl/qt5/QtGraphics.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtGraphics.hxx> + +#include <QtData.hxx> +#include <QtFont.hxx> +#include <QtFrame.hxx> +#include <QtGraphics_Controls.hxx> +#include <QtPainter.hxx> + +#include <QtGui/QImage> +#include <QtGui/QPainter> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QWidget> + +QtGraphics::QtGraphics( QtFrame *pFrame, QImage *pQImage ) + : m_pFrame( pFrame ) + , m_pTextStyle{ nullptr, } + , m_aTextColor( 0x00, 0x00, 0x00 ) +{ + m_pBackend = std::make_unique<QtGraphicsBackend>(m_pFrame, pQImage); + + if (!initWidgetDrawBackends(false)) + { + if (!QtData::noNativeControls()) + m_pWidgetDraw.reset(new QtGraphics_Controls(*this)); + } + if (m_pFrame) + setDevicePixelRatioF(m_pFrame->devicePixelRatioF()); +} + +QtGraphics::~QtGraphics() { ReleaseFonts(); } + +void QtGraphics::ChangeQImage(QImage* pQImage) +{ + m_pBackend->setQImage(pQImage); + m_pBackend->ResetClipRegion(); +} + +SalGraphicsImpl* QtGraphics::GetImpl() const { return m_pBackend.get(); } + +SystemGraphicsData QtGraphics::GetGraphicsData() const { return SystemGraphicsData(); } + +#if ENABLE_CAIRO_CANVAS + +bool QtGraphics::SupportsCairo() const { return false; } + +cairo::SurfaceSharedPtr +QtGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& /*rSurface*/) const +{ + return nullptr; +} + +cairo::SurfaceSharedPtr QtGraphics::CreateSurface(const OutputDevice& /*rRefDevice*/, int /*x*/, + int /*y*/, int /*width*/, int /*height*/) const +{ + return nullptr; +} + +cairo::SurfaceSharedPtr QtGraphics::CreateBitmapSurface(const OutputDevice& /*rRefDevice*/, + const BitmapSystemData& /*rData*/, + const Size& /*rSize*/) const +{ + return nullptr; +} + +css::uno::Any QtGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*rSurface*/, + const basegfx::B2ISize& /*rSize*/) const +{ + return css::uno::Any(); +} + +#endif + +void QtGraphics::handleDamage(const tools::Rectangle& rDamagedRegion) +{ + assert(m_pWidgetDraw); + assert(dynamic_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())); + assert(!rDamagedRegion.IsEmpty()); + + QImage* pImage = static_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())->getImage(); + QImage blit(*pImage); + blit.setDevicePixelRatio(1); + QtPainter aPainter(*m_pBackend); + aPainter.drawImage(QPoint(rDamagedRegion.Left(), rDamagedRegion.Top()), blit); + aPainter.update(toQRect(rDamagedRegion)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtGraphics_Controls.cxx b/vcl/qt5/QtGraphics_Controls.cxx new file mode 100644 index 000000000000..e6e3d820da59 --- /dev/null +++ b/vcl/qt5/QtGraphics_Controls.cxx @@ -0,0 +1,1134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtGraphics_Controls.hxx> + +#include <QtGui/QPainter> +#include <QtWidgets/QApplication> +#include <QtWidgets/QFrame> +#include <QtWidgets/QLabel> + +#include <QtTools.hxx> +#include <QtGraphicsBase.hxx> +#include <vcl/decoview.hxx> + +/** + Conversion function between VCL ControlState together with + ImplControlValue and Qt state flags. + @param nControlState State of the widget (default, focused, ...) in Native Widget Framework. + @param aValue Value held by the widget (on, off, ...) +*/ +static QStyle::State vclStateValue2StateFlag(ControlState nControlState, + const ImplControlValue& aValue) +{ + QStyle::State nState + = ((nControlState & ControlState::ENABLED) ? QStyle::State_Enabled : QStyle::State_None) + | ((nControlState & ControlState::FOCUSED) ? QStyle::State_HasFocus : QStyle::State_None) + | ((nControlState & ControlState::PRESSED) ? QStyle::State_Sunken : QStyle::State_None) + | ((nControlState & ControlState::SELECTED) ? QStyle::State_Selected : QStyle::State_None) + | ((nControlState & ControlState::ROLLOVER) ? QStyle::State_MouseOver + : QStyle::State_None); + + switch (aValue.getTristateVal()) + { + case ButtonValue::On: + nState |= QStyle::State_On; + break; + case ButtonValue::Off: + nState |= QStyle::State_Off; + break; + case ButtonValue::Mixed: + nState |= QStyle::State_NoChange; + break; + default: + break; + } + + return nState; +} + +static void lcl_ApplyBackgroundColorToStyleOption(QStyleOption& rOption, + const Color& rBackgroundColor) +{ + if (rBackgroundColor != COL_AUTO) + { + QColor aColor = toQColor(rBackgroundColor); + for (QPalette::ColorRole role : { QPalette::Window, QPalette::Button, QPalette::Base }) + rOption.palette.setColor(role, aColor); + } +} + +QtGraphics_Controls::QtGraphics_Controls(const QtGraphicsBase& rGraphics) + : m_rGraphics(rGraphics) +{ +} + +bool QtGraphics_Controls::isNativeControlSupported(ControlType type, ControlPart part) +{ + switch (type) + { + case ControlType::Tooltip: + case ControlType::Progress: + case ControlType::ListNode: + return (part == ControlPart::Entire); + + case ControlType::Radiobutton: + case ControlType::Checkbox: + return (part == ControlPart::Entire) || (part == ControlPart::Focus); + case ControlType::Pushbutton: + return (part == ControlPart::Entire); + + case ControlType::ListHeader: + return (part == ControlPart::Button); + + case ControlType::Menubar: + case ControlType::MenuPopup: + case ControlType::Editbox: + case ControlType::MultilineEditbox: + case ControlType::Combobox: + case ControlType::Toolbar: + case ControlType::Frame: + case ControlType::Scrollbar: + case ControlType::WindowBackground: + case ControlType::Fixedline: + return true; + + case ControlType::Listbox: + return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture); + + case ControlType::Spinbox: + return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture); + + case ControlType::Slider: + return (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea); + + case ControlType::TabItem: + case ControlType::TabPane: + return ((part == ControlPart::Entire) || part == ControlPart::TabPaneWithHeader); + + default: + break; + } + + return false; +} + +inline int QtGraphics_Controls::pixelMetric(QStyle::PixelMetric metric, const QStyleOption* option) +{ + return QApplication::style()->pixelMetric(metric, option); +} + +inline QSize QtGraphics_Controls::sizeFromContents(QStyle::ContentsType type, + const QStyleOption* option, + const QSize& contentsSize) +{ + return QApplication::style()->sizeFromContents(type, option, contentsSize); +} + +inline QRect QtGraphics_Controls::subControlRect(QStyle::ComplexControl control, + const QStyleOptionComplex* option, + QStyle::SubControl subControl) +{ + return QApplication::style()->subControlRect(control, option, subControl); +} + +inline QRect QtGraphics_Controls::subElementRect(QStyle::SubElement element, + const QStyleOption* option) +{ + return QApplication::style()->subElementRect(element, option); +} + +void QtGraphics_Controls::draw(QStyle::ControlElement element, QStyleOption& rOption, QImage* image, + const Color& rBackgroundColor, QStyle::State const state, QRect rect) +{ + const QRect& targetRect = !rect.isNull() ? rect : image->rect(); + + rOption.state |= state; + rOption.rect = downscale(targetRect); + + lcl_ApplyBackgroundColorToStyleOption(rOption, rBackgroundColor); + + QPainter painter(image); + QApplication::style()->drawControl(element, &rOption, &painter); +} + +void QtGraphics_Controls::draw(QStyle::PrimitiveElement element, QStyleOption& rOption, + QImage* image, const Color& rBackgroundColor, + QStyle::State const state, QRect rect) +{ + const QRect& targetRect = !rect.isNull() ? rect : image->rect(); + + rOption.state |= state; + rOption.rect = downscale(targetRect); + + lcl_ApplyBackgroundColorToStyleOption(rOption, rBackgroundColor); + + QPainter painter(image); + QApplication::style()->drawPrimitive(element, &rOption, &painter); +} + +void QtGraphics_Controls::draw(QStyle::ComplexControl element, QStyleOptionComplex& rOption, + QImage* image, const Color& rBackgroundColor, + QStyle::State const state) +{ + const QRect& targetRect = image->rect(); + + rOption.state |= state; + rOption.rect = downscale(targetRect); + + lcl_ApplyBackgroundColorToStyleOption(rOption, rBackgroundColor); + + QPainter painter(image); + QApplication::style()->drawComplexControl(element, &rOption, &painter); +} + +void QtGraphics_Controls::drawFrame(QStyle::PrimitiveElement element, QImage* image, + const Color& rBackgroundColor, QStyle::State const& state, + bool bClip, QStyle::PixelMetric eLineMetric) +{ + const int fw = pixelMetric(eLineMetric); + QStyleOptionFrame option; + option.frameShape = QFrame::StyledPanel; + option.state = QStyle::State_Sunken | state; + option.lineWidth = fw; + + QRect aRect = downscale(image->rect()); + option.rect = aRect; + + lcl_ApplyBackgroundColorToStyleOption(option, rBackgroundColor); + + QPainter painter(image); + if (bClip) + painter.setClipRegion(QRegion(aRect).subtracted(aRect.adjusted(fw, fw, -fw, -fw))); + QApplication::style()->drawPrimitive(element, &option, &painter); +} + +void QtGraphics_Controls::fillQStyleOptionTab(const ImplControlValue& value, QStyleOptionTab& sot) +{ + const TabitemValue& rValue = static_cast<const TabitemValue&>(value); + if (rValue.isFirst()) + sot.position = rValue.isLast() ? QStyleOptionTab::OnlyOneTab : QStyleOptionTab::Beginning; + else if (rValue.isLast()) + sot.position = rValue.isFirst() ? QStyleOptionTab::OnlyOneTab : QStyleOptionTab::End; + else + sot.position = QStyleOptionTab::Middle; +} + +void QtGraphics_Controls::fullQStyleOptionTabWidgetFrame(QStyleOptionTabWidgetFrame& option, + bool bDownscale) +{ + option.state = QStyle::State_Enabled; + option.rightCornerWidgetSize = QSize(0, 0); + option.leftCornerWidgetSize = QSize(0, 0); + int nLineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth); + option.lineWidth = bDownscale ? std::max(1, downscale(nLineWidth, Round::Ceil)) : nLineWidth; + option.midLineWidth = 0; + option.shape = QTabBar::RoundedNorth; +} + +bool QtGraphics_Controls::drawNativeControl(ControlType type, ControlPart part, + const tools::Rectangle& rControlRegion, + ControlState nControlState, + const ImplControlValue& value, const OUString&, + const Color& rBackgroundColor) +{ + bool nativeSupport = isNativeControlSupported(type, part); + if (!nativeSupport) + { + assert(!nativeSupport && "drawNativeControl called without native support!"); + return false; + } + + if (m_lastPopupRect.isValid() + && (type != ControlType::MenuPopup || part != ControlPart::MenuItem)) + m_lastPopupRect = QRect(); + + bool returnVal = true; + + QRect widgetRect = toQRect(rControlRegion); + + //if no image, or resized, make a new image + if (!m_image || m_image->size() != widgetRect.size()) + { + m_image.reset(new QImage(widgetRect.width(), widgetRect.height(), + QImage::Format_ARGB32_Premultiplied)); + m_image->setDevicePixelRatio(m_rGraphics.devicePixelRatioF()); + } + + // Default image color - just once + switch (type) + { + case ControlType::MenuPopup: + if (part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark) + { + // it is necessary to fill the background transparently first, as this + // is painted after menuitem highlight, otherwise there would be a grey area + m_image->fill(Qt::transparent); + break; + } + [[fallthrough]]; // QPalette::Window + case ControlType::Menubar: + case ControlType::WindowBackground: + m_image->fill(QApplication::palette().color(QPalette::Window).rgb()); + break; + case ControlType::Tooltip: + m_image->fill(QApplication::palette().color(QPalette::ToolTipBase).rgb()); + break; + case ControlType::Scrollbar: + if ((part == ControlPart::DrawBackgroundVert) + || (part == ControlPart::DrawBackgroundHorz)) + { + m_image->fill(QApplication::palette().color(QPalette::Window).rgb()); + break; + } + [[fallthrough]]; // Qt::transparent + default: + m_image->fill(Qt::transparent); + break; + } + + if (type == ControlType::Pushbutton) + { + const PushButtonValue& rPBValue = static_cast<const PushButtonValue&>(value); + assert(part == ControlPart::Entire); + QStyleOptionButton option; + if (nControlState & ControlState::DEFAULT) + option.features |= QStyleOptionButton::DefaultButton; + if (rPBValue.m_bFlatButton) + option.features |= QStyleOptionButton::Flat; + draw(QStyle::CE_PushButton, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Menubar) + { + if (part == ControlPart::MenuItem) + { + QStyleOptionMenuItem option; + option.state = vclStateValue2StateFlag(nControlState, value); + if ((nControlState & ControlState::ROLLOVER) + && QApplication::style()->styleHint(QStyle::SH_MenuBar_MouseTracking)) + option.state |= QStyle::State_Selected; + + if (nControlState + & ControlState::SELECTED) // Passing State_Sunken is currently not documented. + option.state |= QStyle::State_Sunken; // But some kinds of QStyle interpret it. + + draw(QStyle::CE_MenuBarItem, option, m_image.get(), rBackgroundColor); + } + else if (part == ControlPart::Entire) + { + QStyleOptionMenuItem option; + draw(QStyle::CE_MenuBarEmptyArea, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else + { + returnVal = false; + } + } + else if (type == ControlType::MenuPopup) + { + assert(part == ControlPart::MenuItem ? m_lastPopupRect.isValid() + : !m_lastPopupRect.isValid()); + if (part == ControlPart::MenuItem) + { + QStyleOptionMenuItem option; + draw(QStyle::CE_MenuItem, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + // HACK: LO core first paints the entire popup and only then it paints menu items, + // but QMenu::paintEvent() paints popup frame after all items. That means highlighted + // items here would paint the highlight over the frame border. Since calls to ControlPart::MenuItem + // are always preceded by calls to ControlPart::Entire, just remember the size for the whole + // popup (otherwise not possible to get here) and draw the border afterwards. + QRect framerect(m_lastPopupRect.topLeft() - widgetRect.topLeft(), + widgetRect.size().expandedTo(m_lastPopupRect.size())); + QStyleOptionFrame frame; + draw(QStyle::PE_FrameMenu, frame, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value), framerect); + } + else if (part == ControlPart::Separator) + { + QStyleOptionMenuItem option; + option.menuItemType = QStyleOptionMenuItem::Separator; + // Painting the whole menu item area results in different background + // with at least Plastique style, so clip only to the separator itself + // (QSize( 2, 2 ) is hardcoded in Qt) + option.rect = m_image->rect(); + QSize size = sizeFromContents(QStyle::CT_MenuItem, &option, QSize(2, 2)); + QRect rect = m_image->rect(); + QPoint center = rect.center(); + rect.setHeight(size.height()); + rect.moveCenter(center); + option.state |= vclStateValue2StateFlag(nControlState, value); + option.rect = rect; + + QPainter painter(m_image.get()); + // don't paint over popup frame border (like the hack above, but here it can be simpler) + const int fw = pixelMetric(QStyle::PM_MenuPanelWidth); + painter.setClipRect(rect.adjusted(fw, 0, -fw, 0)); + QApplication::style()->drawControl(QStyle::CE_MenuItem, &option, &painter); + } + else if (part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark) + { + QStyleOptionMenuItem option; + option.checkType = (part == ControlPart::MenuItemCheckMark) + ? QStyleOptionMenuItem::NonExclusive + : QStyleOptionMenuItem::Exclusive; + option.checked = bool(nControlState & ControlState::PRESSED); + // widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt + // paints the whole menu item, so translate position (and it'll be clipped); + // it is also necessary to fill the background transparently first, as this + // is painted after menuitem highlight, otherwise there would be a grey area + assert(value.getType() == ControlType::MenuPopup); + const MenupopupValue* menuVal = static_cast<const MenupopupValue*>(&value); + QRect menuItemRect(toQRect(menuVal->maItemRect)); + QRect rect(menuItemRect.topLeft() - widgetRect.topLeft(), + widgetRect.size().expandedTo(menuItemRect.size())); + // checkboxes are always displayed next to images in menus, so are never centered + const int focus_size = pixelMetric(QStyle::PM_FocusFrameHMargin); + rect.moveTo(-focus_size, rect.y()); + draw(QStyle::CE_MenuItem, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState & ~ControlState::PRESSED, value), rect); + } + else if (part == ControlPart::Entire) + { + QStyleOptionMenuItem option; + option.state = vclStateValue2StateFlag(nControlState, value); + draw(QStyle::PE_PanelMenu, option, m_image.get(), rBackgroundColor); + // Try hard to get any frame! + QStyleOptionFrame frame; + draw(QStyle::PE_FrameMenu, frame, m_image.get(), rBackgroundColor); + draw(QStyle::PE_FrameWindow, frame, m_image.get(), rBackgroundColor); + m_lastPopupRect = widgetRect; + } + else + returnVal = false; + } + else if ((type == ControlType::Toolbar) && (part == ControlPart::Button)) + { + QStyleOptionToolButton option; + + option.arrowType = Qt::NoArrow; + option.subControls = QStyle::SC_ToolButton; + option.state = vclStateValue2StateFlag(nControlState, value); + option.state |= QStyle::State_Raised | QStyle::State_Enabled | QStyle::State_AutoRaise; + + draw(QStyle::CC_ToolButton, option, m_image.get(), rBackgroundColor); + } + else if ((type == ControlType::Toolbar) && (part == ControlPart::Entire)) + { + QStyleOptionToolBar option; + draw(QStyle::CE_ToolBar, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if ((type == ControlType::Toolbar) + && (part == ControlPart::ThumbVert || part == ControlPart::ThumbHorz)) + { + // reduce paint area only to the handle area + const int handleExtend = pixelMetric(QStyle::PM_ToolBarHandleExtent); + QStyleOption option; + QRect aRect = m_image->rect(); + if (part == ControlPart::ThumbVert) + { + aRect.setWidth(handleExtend); + option.state = QStyle::State_Horizontal; + } + else + aRect.setHeight(handleExtend); + draw(QStyle::PE_IndicatorToolBarHandle, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value), aRect); + } + else if (type == ControlType::Editbox || type == ControlType::MultilineEditbox) + { + drawFrame(QStyle::PE_FrameLineEdit, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value), false); + } + else if (type == ControlType::Combobox) + { + QStyleOptionComboBox option; + option.editable = true; + draw(QStyle::CC_ComboBox, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Listbox) + { + QStyleOptionComboBox option; + option.editable = false; + switch (part) + { + case ControlPart::ListboxWindow: + drawFrame(QStyle::PE_Frame, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value), true, + QStyle::PM_ComboBoxFrameWidth); + break; + case ControlPart::SubEdit: + draw(QStyle::CE_ComboBoxLabel, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + break; + case ControlPart::Entire: + draw(QStyle::CC_ComboBox, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + break; + case ControlPart::ButtonDown: + option.subControls = QStyle::SC_ComboBoxArrow; + draw(QStyle::CC_ComboBox, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + break; + default: + returnVal = false; + break; + } + } + else if (type == ControlType::ListNode) + { + QStyleOption option; + option.state = vclStateValue2StateFlag(nControlState, value); + option.state |= QStyle::State_Item | QStyle::State_Children; + + if (value.getTristateVal() == ButtonValue::On) + option.state |= QStyle::State_Open; + + draw(QStyle::PE_IndicatorBranch, option, m_image.get(), rBackgroundColor); + } + else if (type == ControlType::ListHeader) + { + QStyleOptionHeader option; + draw(QStyle::CE_HeaderSection, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Checkbox) + { + if (part == ControlPart::Entire) + { + QStyleOptionButton option; + // clear FOCUSED bit, focus is drawn separately + nControlState &= ~ControlState::FOCUSED; + draw(QStyle::CE_CheckBox, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (part == ControlPart::Focus) + { + QStyleOptionFocusRect option; + draw(QStyle::PE_FrameFocusRect, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + } + else if (type == ControlType::Scrollbar) + { + if ((part == ControlPart::DrawBackgroundVert) || (part == ControlPart::DrawBackgroundHorz)) + { + QStyleOptionSlider option; + assert(value.getType() == ControlType::Scrollbar); + const ScrollbarValue* sbVal = static_cast<const ScrollbarValue*>(&value); + + //if the scroll bar is active (aka not degenerate... allow for hover events) + if (sbVal->mnVisibleSize < sbVal->mnMax) + option.state = QStyle::State_MouseOver; + + bool horizontal = (part == ControlPart::DrawBackgroundHorz); //horizontal or vertical + option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; + if (horizontal) + option.state |= QStyle::State_Horizontal; + + // If the scrollbar has a mnMin == 0 and mnMax == 0 then mnVisibleSize is set to -1?! + // I don't know if a negative mnVisibleSize makes any sense, so just handle this case + // without crashing LO with a SIGFPE in the Qt library. + const tools::Long nVisibleSize + = (sbVal->mnMin == sbVal->mnMax) ? 0 : sbVal->mnVisibleSize; + + option.minimum = sbVal->mnMin; + option.maximum = sbVal->mnMax - nVisibleSize; + option.maximum = qMax(option.maximum, option.minimum); // bnc#619772 + option.sliderValue = sbVal->mnCur; + option.sliderPosition = sbVal->mnCur; + option.pageStep = nVisibleSize; + if (part == ControlPart::DrawBackgroundHorz) + option.upsideDown + = (QGuiApplication::isRightToLeft() + && sbVal->maButton1Rect.Left() < sbVal->maButton2Rect.Left()) + || (QGuiApplication::isLeftToRight() + && sbVal->maButton1Rect.Left() > sbVal->maButton2Rect.Left()); + + //setup the active control... always the slider + if (sbVal->mnThumbState & ControlState::ROLLOVER) + option.activeSubControls = QStyle::SC_ScrollBarSlider; + + draw(QStyle::CC_ScrollBar, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else + { + returnVal = false; + } + } + else if (type == ControlType::Spinbox) + { + QStyleOptionSpinBox option; + option.frame = true; + + // determine active control + if (value.getType() == ControlType::SpinButtons) + { + const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue*>(&value); + if (pSpinVal->mnUpperState & ControlState::PRESSED) + option.activeSubControls |= QStyle::SC_SpinBoxUp; + if (pSpinVal->mnLowerState & ControlState::PRESSED) + option.activeSubControls |= QStyle::SC_SpinBoxDown; + if (pSpinVal->mnUpperState & ControlState::ENABLED) + option.stepEnabled |= QAbstractSpinBox::StepUpEnabled; + if (pSpinVal->mnLowerState & ControlState::ENABLED) + option.stepEnabled |= QAbstractSpinBox::StepDownEnabled; + if (pSpinVal->mnUpperState & ControlState::ROLLOVER) + option.state = QStyle::State_MouseOver; + if (pSpinVal->mnLowerState & ControlState::ROLLOVER) + option.state = QStyle::State_MouseOver; + } + + draw(QStyle::CC_SpinBox, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Radiobutton) + { + if (part == ControlPart::Entire) + { + QStyleOptionButton option; + // clear FOCUSED bit, focus is drawn separately + nControlState &= ~ControlState::FOCUSED; + draw(QStyle::CE_RadioButton, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (part == ControlPart::Focus) + { + QStyleOptionFocusRect option; + draw(QStyle::PE_FrameFocusRect, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + } + else if (type == ControlType::Tooltip) + { + QStyleOption option; + draw(QStyle::PE_PanelTipLabel, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Frame) + { + drawFrame(QStyle::PE_Frame, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::WindowBackground) + { + // Nothing to do - see "Default image color" switch ^^ + } + else if (type == ControlType::Fixedline) + { + QStyleOptionMenuItem option; + option.menuItemType = QStyleOptionMenuItem::Separator; + option.state = vclStateValue2StateFlag(nControlState, value); + option.state |= QStyle::State_Item; + + draw(QStyle::CE_MenuItem, option, m_image.get(), rBackgroundColor); + } + else if (type == ControlType::Slider + && (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea)) + { + assert(value.getType() == ControlType::Slider); + const SliderValue* slVal = static_cast<const SliderValue*>(&value); + QStyleOptionSlider option; + + option.state = vclStateValue2StateFlag(nControlState, value); + option.maximum = slVal->mnMax; + option.minimum = slVal->mnMin; + option.sliderPosition = option.sliderValue = slVal->mnCur; + bool horizontal = (part == ControlPart::TrackHorzArea); //horizontal or vertical + option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; + if (horizontal) + option.state |= QStyle::State_Horizontal; + + draw(QStyle::CC_Slider, option, m_image.get(), rBackgroundColor); + } + else if (type == ControlType::Progress && part == ControlPart::Entire) + { + QStyleOptionProgressBar option; + option.minimum = 0; + option.maximum = widgetRect.width(); + option.progress = value.getNumericVal(); + + draw(QStyle::CE_ProgressBar, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::TabItem && part == ControlPart::Entire) + { + QStyleOptionTab sot; + fillQStyleOptionTab(value, sot); + draw(QStyle::CE_TabBarTabShape, sot, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::TabPane && part == ControlPart::Entire) + { + const TabPaneValue& rValue = static_cast<const TabPaneValue&>(value); + + // get the overlap size for the tabs, so they will overlap the frame + QStyleOptionTab tabOverlap; + tabOverlap.shape = QTabBar::RoundedNorth; + TabPaneValue::m_nOverlap = pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap); + + QStyleOptionTabWidgetFrame option; + fullQStyleOptionTabWidgetFrame(option, false); + option.tabBarRect = toQRect(rValue.m_aTabHeaderRect); + option.selectedTabRect + = rValue.m_aSelectedTabRect.IsEmpty() ? QRect() : toQRect(rValue.m_aSelectedTabRect); + option.tabBarSize = toQSize(rValue.m_aTabHeaderRect.GetSize()); + option.rect = m_image->rect(); + QRect aRect = subElementRect(QStyle::SE_TabWidgetTabPane, &option); + draw(QStyle::PE_FrameTabWidget, option, m_image.get(), rBackgroundColor, + vclStateValue2StateFlag(nControlState, value), aRect); + } + else + { + returnVal = false; + } + + return returnVal; +} + +bool QtGraphics_Controls::getNativeControlRegion(ControlType type, ControlPart part, + const tools::Rectangle& controlRegion, + ControlState controlState, + const ImplControlValue& val, const OUString&, + tools::Rectangle& nativeBoundingRegion, + tools::Rectangle& nativeContentRegion) +{ + bool retVal = false; + + QRect boundingRect = toQRect(controlRegion); + QRect contentRect = boundingRect; + QStyleOptionComplex styleOption; + + switch (type) + { + // Metrics of the push button + case ControlType::Pushbutton: + if (part == ControlPart::Entire) + { + styleOption.state = vclStateValue2StateFlag(controlState, val); + + if (controlState & ControlState::DEFAULT) + { + int size = upscale(pixelMetric(QStyle::PM_ButtonDefaultIndicator, &styleOption), + Round::Ceil); + boundingRect.adjust(-size, -size, size, size); + retVal = true; + } + } + break; + case ControlType::Editbox: + case ControlType::MultilineEditbox: + { + // we have to get stable borders, otherwise layout loops. + // so we simply only scale the detected borders. + QStyleOptionFrame fo; + fo.frameShape = QFrame::StyledPanel; + fo.state = QStyle::State_Sunken; + fo.lineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth); + fo.rect = downscale(contentRect); + fo.rect.setSize(sizeFromContents(QStyle::CT_LineEdit, &fo, fo.rect.size())); + QRect aSubRect = subElementRect(QStyle::SE_LineEditContents, &fo); + + // VCL tests borders with small defaults before layout, where Qt returns no sub-rect, + // so this gets us at least some frame. + int nLine = upscale(fo.lineWidth, Round::Ceil); + int nLeft = qMin(-nLine, upscale(fo.rect.left() - aSubRect.left(), Round::Floor)); + int nTop = qMin(-nLine, upscale(fo.rect.top() - aSubRect.top(), Round::Floor)); + int nRight = qMax(nLine, upscale(fo.rect.right() - aSubRect.right(), Round::Ceil)); + int nBottom = qMax(nLine, upscale(fo.rect.bottom() - aSubRect.bottom(), Round::Ceil)); + boundingRect.adjust(nLeft, nTop, nRight, nBottom); + retVal = true; + break; + } + case ControlType::Checkbox: + if (part == ControlPart::Entire) + { + styleOption.state = vclStateValue2StateFlag(controlState, val); + + int nWidth = pixelMetric(QStyle::PM_IndicatorWidth, &styleOption); + int nHeight = pixelMetric(QStyle::PM_IndicatorHeight, &styleOption); + contentRect.setSize(upscale(QSize(nWidth, nHeight), Round::Ceil)); + + int nHMargin = pixelMetric(QStyle::PM_FocusFrameHMargin, &styleOption); + int nVMargin = pixelMetric(QStyle::PM_FocusFrameVMargin, &styleOption); + contentRect.adjust(0, 0, 2 * upscale(nHMargin, Round::Ceil), + 2 * upscale(nVMargin, Round::Ceil)); + + boundingRect = contentRect; + retVal = true; + } + break; + case ControlType::Combobox: + case ControlType::Listbox: + { + QStyleOptionComboBox cbo; + + cbo.rect = downscale(QRect(0, 0, contentRect.width(), contentRect.height())); + cbo.state = vclStateValue2StateFlag(controlState, val); + + switch (part) + { + case ControlPart::Entire: + { + // find out the minimum size that should be used + // assume contents is a text line + QSize aContentSize = downscale(contentRect.size(), Round::Ceil); + QFontMetrics aFontMetrics(QApplication::font()); + aContentSize.setHeight(aFontMetrics.height()); + QSize aMinSize = upscale( + sizeFromContents(QStyle::CT_ComboBox, &cbo, aContentSize), Round::Ceil); + if (aMinSize.height() > contentRect.height()) + contentRect.setHeight(aMinSize.height()); + boundingRect = contentRect; + retVal = true; + break; + } + case ControlPart::ButtonDown: + { + contentRect = upscale( + subControlRect(QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxArrow)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + } + case ControlPart::SubEdit: + { + contentRect = upscale( + subControlRect(QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + } + default: + break; + } + break; + } + case ControlType::Spinbox: + { + QStyleOptionSpinBox sbo; + sbo.frame = true; + + sbo.rect = downscale(QRect(0, 0, contentRect.width(), contentRect.height())); + sbo.state = vclStateValue2StateFlag(controlState, val); + + switch (part) + { + case ControlPart::Entire: + { + QSize aContentSize = downscale(contentRect.size(), Round::Ceil); + QFontMetrics aFontMetrics(QApplication::font()); + aContentSize.setHeight(aFontMetrics.height()); + QSize aMinSize = upscale( + sizeFromContents(QStyle::CT_SpinBox, &sbo, aContentSize), Round::Ceil); + if (aMinSize.height() > contentRect.height()) + contentRect.setHeight(aMinSize.height()); + boundingRect = contentRect; + retVal = true; + break; + } + case ControlPart::ButtonUp: + contentRect + = upscale(subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + case ControlPart::ButtonDown: + contentRect + = upscale(subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + case ControlPart::SubEdit: + contentRect = upscale( + subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + default: + break; + } + break; + } + case ControlType::MenuPopup: + { + int h, w; + switch (part) + { + case ControlPart::MenuItemCheckMark: + h = upscale(pixelMetric(QStyle::PM_IndicatorHeight), Round::Floor); + w = upscale(pixelMetric(QStyle::PM_IndicatorWidth), Round::Floor); + retVal = true; + break; + case ControlPart::MenuItemRadioMark: + h = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorHeight), Round::Floor); + w = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorWidth), Round::Floor); + retVal = true; + break; + default: + break; + } + if (retVal) + { + contentRect = QRect(0, 0, w, h); + boundingRect = contentRect; + } + break; + } + case ControlType::Frame: + { + if (part == ControlPart::Border) + { + int nFrameWidth = upscale(pixelMetric(QStyle::PM_DefaultFrameWidth), Round::Ceil); + contentRect.adjust(nFrameWidth, nFrameWidth, -nFrameWidth, -nFrameWidth); + retVal = true; + } + break; + } + case ControlType::Radiobutton: + { + const int h = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorHeight), Round::Ceil); + const int w = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorWidth), Round::Ceil); + + contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h); + int nHMargin = pixelMetric(QStyle::PM_FocusFrameHMargin, &styleOption); + int nVMargin = pixelMetric(QStyle::PM_FocusFrameVMargin, &styleOption); + contentRect.adjust(0, 0, upscale(2 * nHMargin, Round::Ceil), + upscale(2 * nVMargin, Round::Ceil)); + boundingRect = contentRect; + + retVal = true; + break; + } + case ControlType::Slider: + { + const int w = upscale(pixelMetric(QStyle::PM_SliderLength), Round::Ceil); + if (part == ControlPart::ThumbHorz) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height()); + boundingRect = contentRect; + retVal = true; + } + else if (part == ControlPart::ThumbVert) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w); + boundingRect = contentRect; + retVal = true; + } + break; + } + case ControlType::Toolbar: + { + const int nWorH = upscale(pixelMetric(QStyle::PM_ToolBarHandleExtent), Round::Ceil); + if (part == ControlPart::ThumbHorz) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), nWorH); + boundingRect = contentRect; + retVal = true; + } + else if (part == ControlPart::ThumbVert) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), nWorH, boundingRect.height()); + boundingRect = contentRect; + retVal = true; + } + else if (part == ControlPart::Button) + { + QStyleOptionToolButton option; + option.arrowType = Qt::NoArrow; + option.features = QStyleOptionToolButton::None; + option.rect = downscale(QRect({ 0, 0 }, contentRect.size())); + contentRect = upscale( + subControlRect(QStyle::CC_ToolButton, &option, QStyle::SC_ToolButton)); + boundingRect = contentRect; + retVal = true; + } + break; + } + case ControlType::Scrollbar: + { + // core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(), + // for the rest also provide the track area (i.e. area not taken by buttons) + if (part == ControlPart::TrackVertArea || part == ControlPart::TrackHorzArea) + { + QStyleOptionSlider option; + bool horizontal = (part == ControlPart::TrackHorzArea); //horizontal or vertical + option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; + if (horizontal) + option.state |= QStyle::State_Horizontal; + // getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper + // subclass), so use random sensible values (doesn't matter anyway, as the wanted + // geometry here depends only on button sizes) + option.maximum = 10; + option.minimum = 0; + option.sliderPosition = option.sliderValue = 4; + option.pageStep = 2; + // Adjust coordinates to make the widget appear to be at (0,0), i.e. make + // widget and screen coordinates the same. QStyle functions should use screen + // coordinates but at least QPlastiqueStyle::subControlRect() is buggy + // and sometimes uses widget coordinates. + option.rect = downscale(QRect({ 0, 0 }, contentRect.size())); + contentRect = upscale( + subControlRect(QStyle::CC_ScrollBar, &option, QStyle::SC_ScrollBarGroove)); + contentRect.translate(boundingRect.left() + - (contentRect.width() - boundingRect.width()), + boundingRect.top()); + boundingRect = contentRect; + retVal = true; + } + break; + } + case ControlType::TabItem: + { + QStyleOptionTab sot; + fillQStyleOptionTab(val, sot); + QSize aMinSize = upscale(sizeFromContents(QStyle::CT_TabBarTab, &sot, + downscale(contentRect.size(), Round::Ceil)), + Round::Ceil); + contentRect.setSize(aMinSize); + boundingRect = contentRect; + retVal = true; + break; + } + case ControlType::TabPane: + { + const TabPaneValue& rValue = static_cast<const TabPaneValue&>(val); + QStyleOptionTabWidgetFrame sotwf; + fullQStyleOptionTabWidgetFrame(sotwf, true); + QSize contentSize( + std::max(rValue.m_aTabHeaderRect.GetWidth(), controlRegion.GetWidth()), + rValue.m_aTabHeaderRect.GetHeight() + controlRegion.GetHeight()); + QSize aMinSize = upscale( + sizeFromContents(QStyle::CT_TabWidget, &sotwf, downscale(contentSize, Round::Ceil)), + Round::Ceil); + contentRect.setSize(aMinSize); + boundingRect = contentRect; + retVal = true; + break; + } + default: + break; + } + if (retVal) + { + nativeBoundingRegion = toRectangle(boundingRect); + nativeContentRegion = toRectangle(contentRect); + } + + return retVal; +} + +/** Test whether the position is in the native widget. + If the return value is true, bIsInside contains information whether + aPos was or was not inside the native widget specified by the + nType/nPart combination. +*/ +bool QtGraphics_Controls::hitTestNativeControl(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, + const Point& rPos, bool& rIsInside) +{ + if (nType == ControlType::Scrollbar) + { + if (nPart != ControlPart::ButtonUp && nPart != ControlPart::ButtonDown + && nPart != ControlPart::ButtonLeft && nPart != ControlPart::ButtonRight) + { // we adjust only for buttons (because some scrollbars have 3 buttons, + // and LO core doesn't handle such scrollbars well) + return false; + } + rIsInside = false; + bool bHorizontal = (nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight); + QRect rect = toQRect(rControlRegion); + QPoint pos(rPos.X(), rPos.Y()); + // Adjust coordinates to make the widget appear to be at (0,0), i.e. make + // widget and screen coordinates the same. QStyle functions should use screen + // coordinates but at least QPlastiqueStyle::subControlRect() is buggy + // and sometimes uses widget coordinates. + pos -= rect.topLeft(); + rect.moveTo(0, 0); + QStyleOptionSlider options; + options.orientation = bHorizontal ? Qt::Horizontal : Qt::Vertical; + if (bHorizontal) + options.state |= QStyle::State_Horizontal; + options.rect = rect; + // some random sensible values, since we call this code only for scrollbar buttons, + // the slider position does not exactly matter + options.maximum = 10; + options.minimum = 0; + options.sliderPosition = options.sliderValue = 4; + options.pageStep = 2; + QStyle::SubControl control + = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, &options, pos); + if (nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonLeft) + rIsInside = (control == QStyle::SC_ScrollBarSubLine); + else // DOWN, RIGHT + rIsInside = (control == QStyle::SC_ScrollBarAddLine); + return true; + } + return false; +} + +inline int QtGraphics_Controls::downscale(int size, Round eRound) +{ + return static_cast<int>(eRound == Round::Ceil ? ceil(size / m_rGraphics.devicePixelRatioF()) + : floor(size / m_rGraphics.devicePixelRatioF())); +} + +inline int QtGraphics_Controls::upscale(int size, Round eRound) +{ + return static_cast<int>(eRound == Round::Ceil ? ceil(size * m_rGraphics.devicePixelRatioF()) + : floor(size * m_rGraphics.devicePixelRatioF())); +} + +inline QRect QtGraphics_Controls::downscale(const QRect& rect) +{ + return QRect(downscale(rect.x(), Round::Floor), downscale(rect.y(), Round::Floor), + downscale(rect.width(), Round::Ceil), downscale(rect.height(), Round::Ceil)); +} + +inline QRect QtGraphics_Controls::upscale(const QRect& rect) +{ + return QRect(upscale(rect.x(), Round::Floor), upscale(rect.y(), Round::Floor), + upscale(rect.width(), Round::Ceil), upscale(rect.height(), Round::Ceil)); +} + +inline QSize QtGraphics_Controls::downscale(const QSize& size, Round eRound) +{ + return QSize(downscale(size.width(), eRound), downscale(size.height(), eRound)); +} + +inline QSize QtGraphics_Controls::upscale(const QSize& size, Round eRound) +{ + return QSize(upscale(size.width(), eRound), upscale(size.height(), eRound)); +} + +inline QPoint QtGraphics_Controls::upscale(const QPoint& point, Round eRound) +{ + return QPoint(upscale(point.x(), eRound), upscale(point.y(), eRound)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtGraphics_GDI.cxx b/vcl/qt5/QtGraphics_GDI.cxx new file mode 100644 index 000000000000..0f9faa022d0b --- /dev/null +++ b/vcl/qt5/QtGraphics_GDI.cxx @@ -0,0 +1,757 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtGraphics.hxx> + +#include <QtBitmap.hxx> +#include <QtPainter.hxx> + +#include <sal/log.hxx> + +#include <QtGui/QPainter> +#include <QtGui/QScreen> +#include <QtGui/QWindow> +#include <QtWidgets/QWidget> + +#include <numeric> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> + +QtGraphicsBackend::QtGraphicsBackend(QtFrame* pFrame, QImage* pQImage) + : m_pFrame(pFrame) + , m_pQImage(pQImage) + , m_aLineColor(0x00, 0x00, 0x00) + , m_aFillColor(0xFF, 0xFF, 0XFF) + , m_eCompositionMode(QPainter::CompositionMode_SourceOver) +{ + ResetClipRegion(); +} + +QtGraphicsBackend::~QtGraphicsBackend() {} + +const basegfx::B2DPoint aHalfPointOfs(0.5, 0.5); + +static void AddPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolygon& rPolygon, + bool bClosePath, bool bPixelSnap, bool bLineDraw) +{ + const int nPointCount = rPolygon.count(); + // short circuit if there is nothing to do + if (nPointCount == 0) + return; + + const bool bHasCurves = rPolygon.areControlPointsUsed(); + for (int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++) + { + int nClosedIdx = nPointIdx; + if (nPointIdx >= nPointCount) + { + // prepare to close last curve segment if needed + if (bClosePath && (nPointIdx == nPointCount)) + nClosedIdx = 0; + else + break; + } + + basegfx::B2DPoint aPoint = rPolygon.getB2DPoint(nClosedIdx); + + if (bPixelSnap) + { + // snap device coordinates to full pixels + aPoint.setX(basegfx::fround(aPoint.getX())); + aPoint.setY(basegfx::fround(aPoint.getY())); + } + + if (bLineDraw) + aPoint += aHalfPointOfs; + if (!nPointIdx) + { + // first point => just move there + rPath.moveTo(aPoint.getX(), aPoint.getY()); + continue; + } + + bool bPendingCurve = false; + if (bHasCurves) + { + bPendingCurve = rPolygon.isNextControlPointUsed(nPrevIdx); + bPendingCurve |= rPolygon.isPrevControlPointUsed(nClosedIdx); + } + + if (!bPendingCurve) // line segment + rPath.lineTo(aPoint.getX(), aPoint.getY()); + else // cubic bezier segment + { + basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint(nPrevIdx); + basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint(nClosedIdx); + if (bLineDraw) + { + aCP1 += aHalfPointOfs; + aCP2 += aHalfPointOfs; + } + rPath.cubicTo(aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(), aPoint.getX(), + aPoint.getY()); + } + } + + if (bClosePath) + rPath.closeSubpath(); +} + +static bool AddPolyPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolyPolygon& rPolyPoly, + bool bPixelSnap, bool bLineDraw) +{ + if (rPolyPoly.count() == 0) + return false; + for (auto const& rPolygon : rPolyPoly) + { + AddPolygonToPath(rPath, rPolygon, true, bPixelSnap, bLineDraw); + } + return true; +} + +bool QtGraphicsBackend::setClipRegion(const vcl::Region& rRegion) +{ + if (rRegion.IsRectangle()) + { + m_aClipRegion = toQRect(rRegion.GetBoundRect()); + if (!m_aClipPath.isEmpty()) + { + QPainterPath aPath; + m_aClipPath.swap(aPath); + } + } + else if (!rRegion.HasPolyPolygonOrB2DPolyPolygon()) + { + QRegion aQRegion; + RectangleVector aRectangles; + rRegion.GetRegionRectangles(aRectangles); + for (const auto& rRect : aRectangles) + aQRegion += toQRect(rRect); + m_aClipRegion = aQRegion; + if (!m_aClipPath.isEmpty()) + { + QPainterPath aPath; + m_aClipPath.swap(aPath); + } + } + else + { + QPainterPath aPath; + const basegfx::B2DPolyPolygon aPolyClip(rRegion.GetAsB2DPolyPolygon()); + AddPolyPolygonToPath(aPath, aPolyClip, !getAntiAlias(), false); + m_aClipPath.swap(aPath); + if (!m_aClipRegion.isEmpty()) + { + QRegion aRegion; + m_aClipRegion.swap(aRegion); + } + } + return true; +} + +void QtGraphicsBackend::ResetClipRegion() +{ + if (m_pQImage) + m_aClipRegion = QRegion(m_pQImage->rect()); + else + m_aClipRegion = QRegion(); + if (!m_aClipPath.isEmpty()) + { + QPainterPath aPath; + m_aClipPath.swap(aPath); + } +} + +void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY) +{ + QtPainter aPainter(*this); + aPainter.drawPoint(nX, nY); + aPainter.update(nX, nY, 1, 1); +} + +void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY, Color nColor) +{ + QtPainter aPainter(*this); + aPainter.setPen(toQColor(nColor)); + aPainter.setPen(Qt::SolidLine); + aPainter.drawPoint(nX, nY); + aPainter.update(nX, nY, 1, 1); +} + +void QtGraphicsBackend::drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2) +{ + QtPainter aPainter(*this); + aPainter.drawLine(nX1, nY1, nX2, nY2); + + tools::Long tmp; + if (nX1 > nX2) + { + tmp = nX1; + nX1 = nX2; + nX2 = tmp; + } + if (nY1 > nY2) + { + tmp = nY1; + nY1 = nY2; + nY2 = tmp; + } + aPainter.update(nX1, nY1, nX2 - nX1 + 1, nY2 - nY1 + 1); +} + +void QtGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) +{ + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return; + + QtPainter aPainter(*this, true); + if (SALCOLOR_NONE != m_aFillColor) + aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush()); + if (SALCOLOR_NONE != m_aLineColor) + aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1); + aPainter.update(nX, nY, nWidth, nHeight); +} + +void QtGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) +{ + if (0 == nPoints) + return; + + QtPainter aPainter(*this); + QPoint* pPoints = new QPoint[nPoints]; + QPoint aTopLeft(pPtAry->getX(), pPtAry->getY()); + QPoint aBottomRight = aTopLeft; + for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry) + { + pPoints[i] = QPoint(pPtAry->getX(), pPtAry->getY()); + if (pPtAry->getX() < aTopLeft.x()) + aTopLeft.setX(pPtAry->getX()); + if (pPtAry->getY() < aTopLeft.y()) + aTopLeft.setY(pPtAry->getY()); + if (pPtAry->getX() > aBottomRight.x()) + aBottomRight.setX(pPtAry->getX()); + if (pPtAry->getY() > aBottomRight.y()) + aBottomRight.setY(pPtAry->getY()); + } + aPainter.drawPolyline(pPoints, nPoints); + delete[] pPoints; + aPainter.update(QRect(aTopLeft, aBottomRight)); +} + +void QtGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) +{ + QtPainter aPainter(*this, true); + QPolygon aPolygon(nPoints); + for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry) + aPolygon.setPoint(i, pPtAry->getX(), pPtAry->getY()); + aPainter.drawPolygon(aPolygon); + aPainter.update(aPolygon.boundingRect()); +} + +void QtGraphicsBackend::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoints, + const Point** ppPtAry) +{ + // ignore invisible polygons + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return; + + QPainterPath aPath; + for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++) + { + const sal_uInt32 nPoints = pPoints[nPoly]; + if (nPoints > 1) + { + const Point* pPtAry = ppPtAry[nPoly]; + aPath.moveTo(pPtAry->getX(), pPtAry->getY()); + pPtAry++; + for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++) + aPath.lineTo(pPtAry->getX(), pPtAry->getY()); + aPath.closeSubpath(); + } + } + + QtPainter aPainter(*this, true); + aPainter.drawPath(aPath); + aPainter.update(aPath.boundingRect()); +} + +bool QtGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) +{ + // ignore invisible polygons + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return true; + if ((fTransparency >= 1.0) || (fTransparency < 0)) + return true; + + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + + QPainterPath aPath; + // ignore empty polygons + if (!AddPolyPolygonToPath(aPath, aPolyPolygon, !getAntiAlias(), m_aLineColor != SALCOLOR_NONE)) + return true; + + QtPainter aPainter(*this, true, 255 * (1.0 - fTransparency)); + aPainter.drawPath(aPath); + aPainter.update(aPath.boundingRect()); + return true; +} + +bool QtGraphicsBackend::drawPolyLineBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/, + const PolyFlags* /*pFlgAry*/) +{ + return false; +} + +bool QtGraphicsBackend::drawPolygonBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/, + const PolyFlags* /*pFlgAry*/) +{ + return false; +} + +bool QtGraphicsBackend::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* /*pPoints*/, + const Point* const* /*pPtAry*/, + const PolyFlags* const* /*pFlgAry*/) +{ + return false; +} + +bool QtGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, double fTransparency, + double fLineWidth, + const std::vector<double>* pStroke, // MM01 + basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, bool bPixelSnapHairline) +{ + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + { + return true; + } + + // MM01 check done for simple reasons + if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0) + { + return true; + } + + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength( + nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + assert(!bStrokeUsed || (bStrokeUsed && pStroke)); + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if (bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing(rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // target for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolyLine); + } + + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline + aPolyPolygonLine.transform(rObjectToDevice); + if (bPixelSnapHairline) + { + aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); + } + + // tdf#124848 get correct LineWidth in discrete coordinates, + if (fLineWidth == 0) // hairline + fLineWidth = 1.0; + else // Adjust line width for object-to-device scale. + fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength(); + + // setup poly-polygon path + QPainterPath aPath; + + // MM01 todo - I assume that this is OKAY to be done in one run for Qt, + // but this NEEDS to be checked/verified + for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAlias(), true); + } + + QtPainter aPainter(*this, false, 255 * (1.0 - fTransparency)); + + // setup line attributes + QPen aPen = aPainter.pen(); + aPen.setWidth(fLineWidth); + + switch (eLineJoin) + { + case basegfx::B2DLineJoin::Bevel: + aPen.setJoinStyle(Qt::BevelJoin); + break; + case basegfx::B2DLineJoin::Round: + aPen.setJoinStyle(Qt::RoundJoin); + break; + case basegfx::B2DLineJoin::NONE: + case basegfx::B2DLineJoin::Miter: + aPen.setMiterLimit(1.0 / sin(fMiterMinimumAngle / 2.0)); + aPen.setJoinStyle(Qt::MiterJoin); + break; + } + + switch (eLineCap) + { + default: // css::drawing::LineCap_BUTT: + aPen.setCapStyle(Qt::FlatCap); + break; + case css::drawing::LineCap_ROUND: + aPen.setCapStyle(Qt::RoundCap); + break; + case css::drawing::LineCap_SQUARE: + aPen.setCapStyle(Qt::SquareCap); + break; + } + + aPainter.setPen(aPen); + aPainter.drawPath(aPath); + aPainter.update(aPath.boundingRect()); + return true; +} + +bool QtGraphicsBackend::drawGradient(const tools::PolyPolygon& /*rPolyPolygon*/, + const Gradient& /*rGradient*/) +{ + return false; +} + +bool QtGraphicsBackend::implDrawGradient(basegfx::B2DPolyPolygon const& /*rPolyPolygon*/, + SalGradient const& /*rGradient*/) +{ + return false; +} + +void QtGraphicsBackend::drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage) +{ + QtPainter aPainter(*this); + QRect aSrcRect(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + QRect aDestRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); + aPainter.drawImage(aDestRect, rImage, aSrcRect); + aPainter.update(aDestRect); +} + +void QtGraphicsBackend::copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, + tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight, + bool /*bWindowInvalidate*/) +{ + if (nDestX == nSrcX && nDestY == nSrcY) + return; + + SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight); + + QImage* pImage = m_pQImage; + QImage aImage = pImage->copy(aTR.mnSrcX, aTR.mnSrcY, aTR.mnSrcWidth, aTR.mnSrcHeight); + pImage = &aImage; + aTR.mnSrcX = 0; + aTR.mnSrcY = 0; + + drawScaledImage(aTR, *pImage); +} + +void QtGraphicsBackend::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + QImage aImage, *pImage; + SalTwoRect aPosAry = rPosAry; + + if (!pSrcGraphics) + { + pImage = m_pQImage; + aImage + = pImage->copy(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + pImage = &aImage; + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + } + else + pImage = static_cast<QtGraphics*>(pSrcGraphics)->getQImage(); + + drawScaledImage(aPosAry, *pImage); +} + +void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + const QImage* pImage = static_cast<const QtBitmap*>(&rSalBitmap)->GetQImage(); + + assert(pImage); + + drawScaledImage(rPosAry, *pImage); +} + +void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/, + const SalBitmap& /*rTransparentBitmap*/) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth); + assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight); +} + +void QtGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/, + Color /*nMaskColor*/) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth); + assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight); +} + +std::shared_ptr<SalBitmap> QtGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY, + tools::Long nWidth, tools::Long nHeight) +{ + return std::make_shared<QtBitmap>(m_pQImage->copy(nX, nY, nWidth, nHeight)); +} + +Color QtGraphicsBackend::getPixel(tools::Long nX, tools::Long nY) +{ + return Color(ColorTransparency, m_pQImage->pixel(nX, nY)); +} + +void QtGraphicsBackend::invert(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight, SalInvert nFlags) +{ + QtPainter aPainter(*this); + if (SalInvert::N50 & nFlags) + { + aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); + QBrush aBrush(Qt::white, Qt::Dense4Pattern); + aPainter.fillRect(nX, nY, nWidth, nHeight, aBrush); + } + else + { + if (SalInvert::TrackFrame & nFlags) + { + aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); + QPen aPen(Qt::white); + aPen.setStyle(Qt::DotLine); + aPainter.setPen(aPen); + aPainter.drawRect(nX, nY, nWidth, nHeight); + } + else + { + aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); + aPainter.fillRect(nX, nY, nWidth, nHeight, Qt::white); + } + } + aPainter.update(nX, nY, nWidth, nHeight); +} + +void QtGraphicsBackend::invert(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/, + SalInvert /*nFlags*/) +{ +} + +bool QtGraphicsBackend::drawEPS(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/, + tools::Long /*nHeight*/, void* /*pPtr*/, sal_uInt32 /*nSize*/) +{ + return false; +} + +bool QtGraphicsBackend::blendBitmap(const SalTwoRect&, const SalBitmap& /*rBitmap*/) +{ + return false; +} + +bool QtGraphicsBackend::blendAlphaBitmap(const SalTwoRect&, const SalBitmap& /*rSrcBitmap*/, + const SalBitmap& /*rMaskBitmap*/, + const SalBitmap& /*rAlphaBitmap*/) +{ + return false; +} + +static bool getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap, + QImage& rAlphaImage) +{ + if (rAlphaBitmap.GetBitCount() != 8 && rAlphaBitmap.GetBitCount() != 1) + { + SAL_WARN("vcl.gdi", "unsupported alpha depth case: " << rAlphaBitmap.GetBitCount()); + return false; + } + + const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage(); + const QImage* pAlpha = static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage(); + rAlphaImage = pBitmap->convertToFormat(Qt_DefaultFormat32); + + if (rAlphaBitmap.GetBitCount() == 8) + { + for (int y = 0; y < rAlphaImage.height(); ++y) + { + uchar* image_line = rAlphaImage.scanLine(y); + const uchar* alpha_line = pAlpha->scanLine(y); + for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4) + image_line[3] = 255 - alpha_line[x]; + } + } + else + { + for (int y = 0; y < rAlphaImage.height(); ++y) + { + uchar* image_line = rAlphaImage.scanLine(y); + const uchar* alpha_line = pAlpha->scanLine(y); + for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4) + { + if (x && !(x % 8)) + ++alpha_line; + if (0 != (*alpha_line & (1 << (7 - x % 8)))) + image_line[3] = 0; + } + } + } + + return true; +} + +bool QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap) +{ + QImage aImage; + if (!getAlphaImage(rSourceBitmap, rAlphaBitmap, aImage)) + return false; + drawScaledImage(rPosAry, aImage); + return true; +} + +bool QtGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap, double fAlpha) +{ + if (fAlpha != 1.0) + return false; + QImage aImage; + if (pAlphaBitmap && !getAlphaImage(rSourceBitmap, *pAlphaBitmap, aImage)) + return false; + else + { + const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage(); + aImage = pBitmap->convertToFormat(Qt_DefaultFormat32); + } + + QtPainter aPainter(*this); + const basegfx::B2DVector aXRel = rX - rNull; + const basegfx::B2DVector aYRel = rY - rNull; + aPainter.setTransform(QTransform(aXRel.getX() / aImage.width(), aXRel.getY() / aImage.width(), + aYRel.getX() / aImage.height(), aYRel.getY() / aImage.height(), + rNull.getX(), rNull.getY())); + aPainter.drawImage(QPoint(0, 0), aImage); + aPainter.update(aImage.rect()); + return true; +} + +bool QtGraphicsBackend::hasFastDrawTransformedBitmap() const { return false; } + +bool QtGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight, sal_uInt8 nTransparency) +{ + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return true; + assert(nTransparency <= 100); + if (nTransparency > 100) + nTransparency = 100; + QtPainter aPainter(*this, true, (100 - nTransparency) * (255.0 / 100)); + if (SALCOLOR_NONE != m_aFillColor) + aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush()); + if (SALCOLOR_NONE != m_aLineColor) + aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1); + aPainter.update(nX, nY, nWidth, nHeight); + return true; +} + +sal_uInt16 QtGraphicsBackend::GetBitCount() const { return getFormatBits(m_pQImage->format()); } + +tools::Long QtGraphicsBackend::GetGraphicsWidth() const { return m_pQImage->width(); } + +void QtGraphicsBackend::SetLineColor() { m_aLineColor = SALCOLOR_NONE; } + +void QtGraphicsBackend::SetLineColor(Color nColor) { m_aLineColor = nColor; } + +void QtGraphicsBackend::SetFillColor() { m_aFillColor = SALCOLOR_NONE; } + +void QtGraphicsBackend::SetFillColor(Color nColor) { m_aFillColor = nColor; } + +void QtGraphicsBackend::SetXORMode(bool bSet, bool) +{ + if (bSet) + m_eCompositionMode = QPainter::CompositionMode_Xor; + else + m_eCompositionMode = QPainter::CompositionMode_SourceOver; +} + +void QtGraphicsBackend::SetROPLineColor(SalROPColor /*nROPColor*/) {} + +void QtGraphicsBackend::SetROPFillColor(SalROPColor /*nROPColor*/) {} + +bool QtGraphicsBackend::supportsOperation(OutDevSupportType eType) const +{ + switch (eType) + { + case OutDevSupportType::B2DDraw: + case OutDevSupportType::TransparentRect: + return true; + default: + return false; + } +} + +void QtGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) +{ + char* pForceDpi; + if ((pForceDpi = getenv("SAL_FORCEDPI"))) + { + OString sForceDPI(pForceDpi); + rDPIX = rDPIY = sForceDPI.toInt32(); + return; + } + + if (!m_pFrame || !m_pFrame->GetQWidget()->window()->windowHandle()) + return; + + QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen(); + rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5; + rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtGraphics_Text.cxx b/vcl/qt5/QtGraphics_Text.cxx new file mode 100644 index 000000000000..3f1e196d6d7a --- /dev/null +++ b/vcl/qt5/QtGraphics_Text.cxx @@ -0,0 +1,354 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <QtGraphics.hxx> +#include <QtFontFace.hxx> +#include <QtFont.hxx> +#include <QtPainter.hxx> + +#include <fontsubset.hxx> +#include <vcl/fontcharmap.hxx> +#include <unx/geninst.h> +#include <unx/fontmanager.hxx> +#include <unx/glyphcache.hxx> +#include <unx/genpspgraphics.h> + +#include <sallayout.hxx> +#include <PhysicalFontCollection.hxx> + +#include <QtGui/QGlyphRun> +#include <QtGui/QFontDatabase> +#include <QtGui/QRawFont> +#include <QtCore/QStringList> + +void QtGraphics::SetTextColor(Color nColor) { m_aTextColor = nColor; } + +void QtGraphics::SetFont(LogicalFontInstance* pReqFont, int nFallbackLevel) +{ + // release the text styles + for (int i = nFallbackLevel; i < MAX_FALLBACK; ++i) + { + if (!m_pTextStyle[i]) + break; + m_pTextStyle[i].clear(); + } + + if (!pReqFont) + return; + + m_pTextStyle[nFallbackLevel] = static_cast<QtFont*>(pReqFont); +} + +void QtGraphics::GetFontMetric(ImplFontMetricDataRef& rFMD, int nFallbackLevel) +{ + QRawFont aRawFont(QRawFont::fromFont(*m_pTextStyle[nFallbackLevel])); + QtFontFace::fillAttributesFromQFont(*m_pTextStyle[nFallbackLevel], *rFMD); + + rFMD->ImplCalcLineSpacing(m_pTextStyle[nFallbackLevel].get()); + + rFMD->SetSlant(0); + rFMD->SetWidth(aRawFont.averageCharWidth()); + + rFMD->SetMinKashida(m_pTextStyle[nFallbackLevel]->GetKashidaWidth()); +} + +FontCharMapRef QtGraphics::GetFontCharMap() const +{ + if (!m_pTextStyle[0]) + return FontCharMapRef(new FontCharMap()); + return m_pTextStyle[0]->GetFontFace()->GetFontCharMap(); +} + +bool QtGraphics::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const +{ + if (!m_pTextStyle[0]) + return false; + return m_pTextStyle[0]->GetFontFace()->GetFontCapabilities(rFontCapabilities); +} + +void QtGraphics::GetDevFontList(PhysicalFontCollection* pPFC) +{ + static const bool bUseFontconfig = (nullptr == getenv("SAL_VCL_QT5_NO_FONTCONFIG")); + + if (pPFC->Count()) + return; + + QFontDatabase aFDB; + FreetypeManager& rFontManager = FreetypeManager::get(); + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + ::std::vector<psp::fontID> aList; + psp::FastPrintFontInfo aInfo; + + rMgr.getFontList(aList); + for (auto const& elem : aList) + { + if (!rMgr.getFontFastInfo(elem, aInfo)) + continue; + + // normalize face number to the FreetypeManager + int nFaceNum = rMgr.getFontFaceNumber(aInfo.m_nID); + int nVariantNum = rMgr.getFontFaceVariation(aInfo.m_nID); + + // inform FreetypeManager about this font provided by the PsPrint subsystem + FontAttributes aDFA = GenPspGraphics::Info2FontAttributes(aInfo); + aDFA.IncreaseQualityBy(4096); + const OString& rFileName = rMgr.getFontFileSysPath(aInfo.m_nID); + rFontManager.AddFontFile(rFileName, nFaceNum, nVariantNum, aInfo.m_nID, aDFA); + } + + if (bUseFontconfig) + SalGenericInstance::RegisterFontSubstitutors(pPFC); + + for (auto& family : aFDB.families()) + for (auto& style : aFDB.styles(family)) + pPFC->Add(QtFontFace::fromQFontDatabase(family, style)); +} + +void QtGraphics::ClearDevFontCache() {} + +bool QtGraphics::AddTempDevFont(PhysicalFontCollection*, const OUString& /*rFileURL*/, + const OUString& /*rFontName*/) +{ + return false; +} + +namespace +{ +class QtTrueTypeFont : public vcl::AbstractTrueTypeFont +{ + const QRawFont& m_aRawFont; + mutable QByteArray m_aFontTable[vcl::NUM_TAGS]; + +public: + QtTrueTypeFont(const QtFontFace& aFontFace, const QRawFont& aRawFont); + + bool hasTable(sal_uInt32 ord) const override; + const sal_uInt8* table(sal_uInt32 ord, sal_uInt32& size) const override; +}; + +QtTrueTypeFont::QtTrueTypeFont(const QtFontFace& aFontFace, const QRawFont& aRawFont) + : vcl::AbstractTrueTypeFont(nullptr, aFontFace.GetFontCharMap()) + , m_aRawFont(aRawFont) +{ + indexGlyphData(); +} + +const char* vclFontTableAsChar(sal_uInt32 ord) +{ + switch (ord) + { + case vcl::O_maxp: + return "maxp"; + case vcl::O_glyf: + return "glyf"; + case vcl::O_head: + return "head"; + case vcl::O_loca: + return "loca"; + case vcl::O_name: + return "name"; + case vcl::O_hhea: + return "hhea"; + case vcl::O_hmtx: + return "hmtx"; + case vcl::O_cmap: + return "cmap"; + case vcl::O_vhea: + return "vhea"; + case vcl::O_vmtx: + return "vmtx"; + case vcl::O_OS2: + return "OS/2"; + case vcl::O_post: + return "post"; + case vcl::O_cvt: + return "cvt "; + case vcl::O_prep: + return "prep"; + case vcl::O_fpgm: + return "fpgm"; + case vcl::O_gsub: + return "gsub"; + case vcl::O_CFF: + return "CFF "; + default: + return nullptr; + } +} + +bool QtTrueTypeFont::hasTable(sal_uInt32 ord) const +{ + const char* table_char = vclFontTableAsChar(ord); + if (!table_char) + return false; + if (m_aFontTable[ord].isEmpty()) + m_aFontTable[ord] = m_aRawFont.fontTable(table_char); + return !m_aFontTable[ord].isEmpty(); +} + +const sal_uInt8* QtTrueTypeFont::table(sal_uInt32 ord, sal_uInt32& size) const +{ + const char* table_char = vclFontTableAsChar(ord); + if (!table_char) + return nullptr; + if (m_aFontTable[ord].isEmpty()) + m_aFontTable[ord] = m_aRawFont.fontTable(table_char); + size = m_aFontTable[ord].size(); + return reinterpret_cast<const sal_uInt8*>(m_aFontTable[ord].data()); +} +} + +bool QtGraphics::CreateFontSubset(const OUString& rToFile, const PhysicalFontFace* pFontFace, + const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, + sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo) +{ + OUString aSysPath; + if (osl_File_E_None != osl_getSystemPathFromFileURL(rToFile.pData, &aSysPath.pData)) + return false; + + // get the raw-bytes from the font to be subset + const QtFontFace* pQtFontFace = static_cast<const QtFontFace*>(pFontFace); + const QFont aFont = pQtFontFace->CreateFont(); + const QRawFont aRawFont(QRawFont::fromFont(aFont)); + const OString aToFile(OUStringToOString(aSysPath, osl_getThreadTextEncoding())); + + // handle CFF-subsetting + QByteArray aCFFtable = aRawFont.fontTable("CFF "); + if (!aCFFtable.isEmpty()) + return SalGraphics::CreateCFFfontSubset( + reinterpret_cast<const sal_uInt8*>(aCFFtable.data()), aCFFtable.size(), aToFile, + pGlyphIds, pEncoding, pGlyphWidths, nGlyphCount, rInfo); + + // fill details about the subsetted font + rInfo.m_nFontType = FontType::SFNT_TTF; + rInfo.m_aPSName = toOUString(aRawFont.familyName()); + rInfo.m_nCapHeight = aRawFont.capHeight(); + rInfo.m_nAscent = aRawFont.ascent(); + rInfo.m_nDescent = aRawFont.descent(); + + QtTrueTypeFont aTTF(*pQtFontFace, aRawFont); + int nXmin, nYmin, nXmax, nYmax; + sal_uInt16 nMacStyleFlags; + if (GetTTGlobalFontHeadInfo(&aTTF, nXmin, nYmin, nXmax, nYmax, nMacStyleFlags)) + rInfo.m_aFontBBox = tools::Rectangle(Point(nXmin, nYmin), Point(nXmax, nYmax)); + + return SalGraphics::CreateTTFfontSubset(aTTF, aToFile, false /* use FontSelectPattern? */, + pGlyphIds, pEncoding, pGlyphWidths, nGlyphCount); +} + +const void* QtGraphics::GetEmbedFontData(const PhysicalFontFace*, tools::Long* /*pDataLen*/) +{ + return nullptr; +} + +void QtGraphics::FreeEmbedFontData(const void* /*pData*/, tools::Long /*nDataLen*/) {} + +void QtGraphics::GetGlyphWidths(const PhysicalFontFace* pFontFace, bool bVertical, + std::vector<sal_Int32>& rWidths, Ucs2UIntMap& rUnicodeEnc) +{ + const QtFontFace* pQtFontFace = static_cast<const QtFontFace*>(pFontFace); + const QRawFont aRawFont(QRawFont::fromFont(pQtFontFace->CreateFont())); + QtTrueTypeFont aTTF(*pQtFontFace, aRawFont); + SalGraphics::GetGlyphWidths(aTTF, *pFontFace, bVertical, rWidths, rUnicodeEnc); +} + +namespace +{ +class QtCommonSalLayout : public GenericSalLayout +{ +public: + QtCommonSalLayout(LogicalFontInstance& rLFI) + : GenericSalLayout(rLFI) + { + } + + void SetOrientation(Degree10 nOrientation) { mnOrientation = nOrientation; } +}; +} + +std::unique_ptr<GenericSalLayout> QtGraphics::GetTextLayout(int nFallbackLevel) +{ + assert(m_pTextStyle[nFallbackLevel]); + if (!m_pTextStyle[nFallbackLevel]) + return nullptr; + return std::make_unique<QtCommonSalLayout>(*m_pTextStyle[nFallbackLevel]); +} + +void QtGraphics::DrawTextLayout(const GenericSalLayout& rLayout) +{ + const QtFont* pFont = static_cast<const QtFont*>(&rLayout.GetFont()); + assert(pFont); + QRawFont aRawFont(QRawFont::fromFont(*pFont)); + + QVector<quint32> glyphIndexes; + QVector<QPointF> positions; + + // prevent glyph rotation inside the SalLayout + // probably better to add a parameter to GetNextGlyphs? + QtCommonSalLayout* pQtLayout + = static_cast<QtCommonSalLayout*>(const_cast<GenericSalLayout*>(&rLayout)); + Degree10 nOrientation = rLayout.GetOrientation(); + if (nOrientation) + pQtLayout->SetOrientation(0_deg10); + + Point aPos; + const GlyphItem* pGlyph; + int nStart = 0; + while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) + { + glyphIndexes.push_back(pGlyph->glyphId()); + positions.push_back(QPointF(aPos.X(), aPos.Y())); + } + + // seems to be common to try to layout an empty string... + if (positions.empty()) + return; + + if (nOrientation) + pQtLayout->SetOrientation(nOrientation); + + QGlyphRun aGlyphRun; + aGlyphRun.setPositions(positions); + aGlyphRun.setGlyphIndexes(glyphIndexes); + aGlyphRun.setRawFont(aRawFont); + + QtPainter aPainter(*m_pBackend); + QColor aColor = toQColor(m_aTextColor); + aPainter.setPen(aColor); + + if (nOrientation) + { + // make text position the center of the rotation + // then rotate and move back + QRect window = aPainter.window(); + window.moveTo(-positions[0].x(), -positions[0].y()); + aPainter.setWindow(window); + + QTransform p; + p.rotate(-static_cast<qreal>(nOrientation.get()) / 10.0); + p.translate(-positions[0].x(), -positions[0].y()); + aPainter.setTransform(p); + } + + aPainter.drawGlyphRun(QPointF(), aGlyphRun); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtInstance.cxx b/vcl/qt5/QtInstance.cxx new file mode 100644 index 000000000000..a41e231b454e --- /dev/null +++ b/vcl/qt5/QtInstance.cxx @@ -0,0 +1,702 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtInstance.hxx> +#include <QtInstance.moc> + +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <QtBitmap.hxx> +#include <QtClipboard.hxx> +#include <QtData.hxx> +#include <QtDragAndDrop.hxx> +#include <QtFilePicker.hxx> +#include <QtFrame.hxx> +#include <QtMenu.hxx> +#include <QtObject.hxx> +#include <QtOpenGLContext.hxx> +#include "QtSvpVirtualDevice.hxx" +#include <QtSystem.hxx> +#include <QtTimer.hxx> +#include <QtVirtualDevice.hxx> + +#include <headless/svpvd.hxx> + +#include <QtCore/QAbstractEventDispatcher> +#include <QtCore/QThread> +#include <QtWidgets/QApplication> +#include <QtWidgets/QWidget> + +#include <vclpluginapi.h> +#include <tools/debug.hxx> +#include <comphelper/flagguard.hxx> +#include <sal/log.hxx> +#include <osl/process.h> +#include <unx/gstsink.hxx> +#include <headless/svpbmp.hxx> + +#include <mutex> +#include <condition_variable> + +#ifdef EMSCRIPTEN +#include <QtCore/QtPlugin> +Q_IMPORT_PLUGIN(QWasmIntegrationPlugin) +#endif + +namespace +{ +/// TODO: not much Qt specific here? could be generalised, esp. for OSX... +/// this subclass allows for the transfer of a closure for running on the main +/// thread, to handle all the thread affine stuff in Qt; the SolarMutex is +/// "loaned" to the main thread for the execution of the closure. +/// @note it doesn't work to just use "emit" and signals/slots to move calls to +/// the main thread, because the other thread has the SolarMutex; the other +/// thread (typically) cannot release SolarMutex, because then the main thread +/// will handle all sorts of events and whatnot; this design ensures that the +/// main thread only runs the passed closure (unless the closure releases +/// SolarMutex itself, which should probably be avoided). +class QtYieldMutex : public SalYieldMutex +{ +public: + /// flag only accessed on main thread: + /// main thread has "borrowed" SolarMutex from another thread + bool m_bNoYieldLock = false; + /// members for communication from non-main thread to main thread + std::mutex m_RunInMainMutex; + std::condition_variable m_InMainCondition; + bool m_isWakeUpMain = false; + std::function<void()> m_Closure; ///< code for main thread to run + /// members for communication from main thread to non-main thread + std::condition_variable m_ResultCondition; + bool m_isResultReady = false; + + virtual bool IsCurrentThread() const override; + virtual void doAcquire(sal_uInt32 nLockCount) override; + virtual sal_uInt32 doRelease(bool const bUnlockAll) override; +}; +} + +bool QtYieldMutex::IsCurrentThread() const +{ + auto const* pSalInst(static_cast<QtInstance const*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (pSalInst->IsMainThread() && m_bNoYieldLock) + { + return true; // main thread has borrowed SolarMutex + } + return SalYieldMutex::IsCurrentThread(); +} + +void QtYieldMutex::doAcquire(sal_uInt32 nLockCount) +{ + auto const* pSalInst(static_cast<QtInstance const*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + SalYieldMutex::doAcquire(nLockCount); + return; + } + if (m_bNoYieldLock) + { + return; // special case for main thread: borrowed from other thread + } + do // main thread acquire... + { + std::function<void()> func; // copy of closure on thread stack + { + std::unique_lock<std::mutex> g(m_RunInMainMutex); + if (m_aMutex.tryToAcquire()) + { + // if there's a closure, the other thread holds m_aMutex + assert(!m_Closure); + m_isWakeUpMain = false; + --nLockCount; // have acquired once! + ++m_nCount; + break; + } + m_InMainCondition.wait(g, [this]() { return m_isWakeUpMain; }); + m_isWakeUpMain = false; + std::swap(func, m_Closure); + } + if (func) + { + assert(!m_bNoYieldLock); + m_bNoYieldLock = true; // execute closure with borrowed SolarMutex + func(); + m_bNoYieldLock = false; + std::scoped_lock<std::mutex> g(m_RunInMainMutex); + assert(!m_isResultReady); + m_isResultReady = true; + m_ResultCondition.notify_all(); // unblock other thread + } + } while (true); + SalYieldMutex::doAcquire(nLockCount); +} + +sal_uInt32 QtYieldMutex::doRelease(bool const bUnlockAll) +{ + auto const* pSalInst(static_cast<QtInstance const*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (pSalInst->IsMainThread() && m_bNoYieldLock) + { + return 1; // dummy value + } + + std::scoped_lock<std::mutex> g(m_RunInMainMutex); + // read m_nCount before doRelease (it's guarded by m_aMutex) + bool const isReleased(bUnlockAll || m_nCount == 1); + sal_uInt32 nCount = SalYieldMutex::doRelease(bUnlockAll); + if (isReleased && !pSalInst->IsMainThread()) + { + m_isWakeUpMain = true; + m_InMainCondition.notify_all(); // unblock main thread + } + return nCount; +} + +// this could be abstracted to be independent of Qt by passing in the +// event-trigger as another function parameter... +// it could also be a template of the return type, then it could return the +// result of func... but then how to handle the result in doAcquire? +void QtInstance::RunInMainThread(std::function<void()> func) +{ + DBG_TESTSOLARMUTEX(); + if (IsMainThread()) + { + func(); + return; + } + + QtYieldMutex* const pMutex(static_cast<QtYieldMutex*>(GetYieldMutex())); + { + std::scoped_lock<std::mutex> g(pMutex->m_RunInMainMutex); + assert(!pMutex->m_Closure); + pMutex->m_Closure = func; + // unblock main thread in case it is blocked on condition + pMutex->m_isWakeUpMain = true; + pMutex->m_InMainCondition.notify_all(); + } + + TriggerUserEventProcessing(); + { + std::unique_lock<std::mutex> g(pMutex->m_RunInMainMutex); + pMutex->m_ResultCondition.wait(g, [pMutex]() { return pMutex->m_isResultReady; }); + pMutex->m_isResultReady = false; + } +} + +OUString QtInstance::constructToolkitID(std::u16string_view sTKname) +{ + OUString sID(sTKname + OUString::Concat(u" (")); + if (m_bUseCairo) + sID += "cairo+"; + else + sID += "qfont+"; + sID += toOUString(QGuiApplication::platformName()) + OUString::Concat(u")"); + return sID; +} + +QtInstance::QtInstance(std::unique_ptr<QApplication>& pQApp, bool bUseCairo) + : SalGenericInstance(std::make_unique<QtYieldMutex>()) + , m_bUseCairo(bUseCairo) + , m_pTimer(nullptr) + , m_bSleeping(false) + , m_pQApplication(std::move(pQApp)) + , m_aUpdateStyleTimer("vcl::qt5 m_aUpdateStyleTimer") + , m_bUpdateFonts(false) +{ + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mxToolkitName = constructToolkitID(u"qt5"); + + // this one needs to be blocking, so that the handling in main thread + // is processed before the thread emitting the signal continues + connect(this, SIGNAL(ImplYieldSignal(bool, bool)), this, SLOT(ImplYield(bool, bool)), + Qt::BlockingQueuedConnection); + + // this one needs to be queued non-blocking + // in order to have this event arriving to correct event processing loop + connect(this, &QtInstance::deleteObjectLaterSignal, this, + [](QObject* pObject) { QtInstance::deleteObjectLater(pObject); }, Qt::QueuedConnection); + + m_aUpdateStyleTimer.SetTimeout(50); + m_aUpdateStyleTimer.SetInvokeHandler(LINK(this, QtInstance, updateStyleHdl)); + + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); + connect(dispatcher, &QAbstractEventDispatcher::awake, this, [this]() { m_bSleeping = false; }); + connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, + [this]() { m_bSleeping = true; }); + + connect(QGuiApplication::inputMethod(), &QInputMethod::localeChanged, this, + &QtInstance::localeChanged); + +#ifndef EMSCRIPTEN + m_bSupportsOpenGL = true; +#endif +} + +QtInstance::~QtInstance() +{ + // force freeing the QApplication before freeing the arguments, + // as it uses references to the provided arguments! + m_pQApplication.reset(); +} + +void QtInstance::AfterAppInit() +{ + // set the default application icon via desktop file just on Wayland, + // as this otherwise overrides the individual desktop icons on X11. + if (QGuiApplication::platformName() == "wayland") + QGuiApplication::setDesktopFileName(QStringLiteral("libreoffice-startcenter.desktop")); + QGuiApplication::setLayoutDirection(AllSettings::GetLayoutRTL() ? Qt::RightToLeft + : Qt::LeftToRight); +} + +void QtInstance::localeChanged() +{ + SolarMutexGuard aGuard; + const vcl::Window* pFocusWindow = Application::GetFocusWindow(); + SalFrame* const pFocusFrame = pFocusWindow ? pFocusWindow->ImplGetFrame() : nullptr; + if (!pFocusFrame) + return; + + const LanguageTag aTag( + toOUString(QGuiApplication::inputMethod()->locale().name().replace("_", "-"))); + static_cast<QtFrame*>(pFocusFrame)->setInputLanguage(aTag.getLanguageType()); +} + +void QtInstance::deleteObjectLater(QObject* pObject) { pObject->deleteLater(); } + +SalFrame* QtInstance::CreateChildFrame(SystemParentData* /*pParent*/, SalFrameStyleFlags nStyle) +{ + SalFrame* pRet(nullptr); + RunInMainThread([&, this]() { pRet = new QtFrame(nullptr, nStyle, useCairo()); }); + assert(pRet); + return pRet; +} + +SalFrame* QtInstance::CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) +{ + assert(!pParent || dynamic_cast<QtFrame*>(pParent)); + + SalFrame* pRet(nullptr); + RunInMainThread( + [&, this]() { pRet = new QtFrame(static_cast<QtFrame*>(pParent), nStyle, useCairo()); }); + assert(pRet); + return pRet; +} + +void QtInstance::DestroyFrame(SalFrame* pFrame) +{ + if (pFrame) + { + assert(dynamic_cast<QtFrame*>(pFrame)); + Q_EMIT deleteObjectLaterSignal(static_cast<QtFrame*>(pFrame)); + } +} + +SalObject* QtInstance::CreateObject(SalFrame* pParent, SystemWindowData*, bool bShow) +{ + assert(!pParent || dynamic_cast<QtFrame*>(pParent)); + + SalObject* pRet(nullptr); + RunInMainThread([&]() { pRet = new QtObject(static_cast<QtFrame*>(pParent), bShow); }); + assert(pRet); + return pRet; +} + +void QtInstance::DestroyObject(SalObject* pObject) +{ + if (pObject) + { + assert(dynamic_cast<QtObject*>(pObject)); + Q_EMIT deleteObjectLaterSignal(static_cast<QtObject*>(pObject)); + } +} + +std::unique_ptr<SalVirtualDevice> +QtInstance::CreateVirtualDevice(SalGraphics& rGraphics, tools::Long& nDX, tools::Long& nDY, + DeviceFormat /*eFormat*/, const SystemGraphicsData* pGd) +{ + if (m_bUseCairo) + { + SvpSalGraphics* pSvpSalGraphics = dynamic_cast<QtSvpGraphics*>(&rGraphics); + assert(pSvpSalGraphics); + // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget + cairo_surface_t* pPreExistingTarget + = pGd ? static_cast<cairo_surface_t*>(pGd->pSurface) : nullptr; + std::unique_ptr<SalVirtualDevice> pVD( + new QtSvpVirtualDevice(pSvpSalGraphics->getSurface(), pPreExistingTarget)); + pVD->SetSize(nDX, nDY); + return pVD; + } + else + { + std::unique_ptr<SalVirtualDevice> pVD(new QtVirtualDevice(/*scale*/ 1)); + pVD->SetSize(nDX, nDY); + return pVD; + } +} + +std::unique_ptr<SalMenu> QtInstance::CreateMenu(bool bMenuBar, Menu* pVCLMenu) +{ + std::unique_ptr<SalMenu> pRet; + RunInMainThread([&pRet, bMenuBar, pVCLMenu]() { + QtMenu* pSalMenu = new QtMenu(bMenuBar); + pRet.reset(pSalMenu); + pSalMenu->SetMenu(pVCLMenu); + }); + assert(pRet); + return pRet; +} + +std::unique_ptr<SalMenuItem> QtInstance::CreateMenuItem(const SalItemParams& rItemData) +{ + return std::unique_ptr<SalMenuItem>(new QtMenuItem(&rItemData)); +} + +SalTimer* QtInstance::CreateSalTimer() +{ + m_pTimer = new QtTimer(); + return m_pTimer; +} + +SalSystem* QtInstance::CreateSalSystem() { return new QtSystem; } + +std::shared_ptr<SalBitmap> QtInstance::CreateSalBitmap() +{ + if (m_bUseCairo) + return std::make_shared<SvpSalBitmap>(); + else + return std::make_shared<QtBitmap>(); +} + +bool QtInstance::ImplYield(bool bWait, bool bHandleAllCurrentEvents) +{ + // Re-acquire the guard for user events when called via Q_EMIT ImplYieldSignal + SolarMutexGuard aGuard; + bool wasEvent = DispatchUserEvents(bHandleAllCurrentEvents); + if (!bHandleAllCurrentEvents && wasEvent) + return true; + + /** + * Quoting the Qt docs: [QAbstractEventDispatcher::processEvents] processes + * pending events that match flags until there are no more events to process. + */ + SolarMutexReleaser aReleaser; + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); + if (bWait && !wasEvent) + wasEvent = dispatcher->processEvents(QEventLoop::WaitForMoreEvents); + else + wasEvent = dispatcher->processEvents(QEventLoop::AllEvents) || wasEvent; + return wasEvent; +} + +bool QtInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) +{ + bool bWasEvent = false; + if (qApp->thread() == QThread::currentThread()) + { + bWasEvent = ImplYield(bWait, bHandleAllCurrentEvents); + if (bWasEvent) + m_aWaitingYieldCond.set(); + } + else + { + { + SolarMutexReleaser aReleaser; + bWasEvent = Q_EMIT ImplYieldSignal(false, bHandleAllCurrentEvents); + } + if (!bWasEvent && bWait) + { + m_aWaitingYieldCond.reset(); + SolarMutexReleaser aReleaser; + m_aWaitingYieldCond.wait(); + bWasEvent = true; + } + } + return bWasEvent; +} + +bool QtInstance::AnyInput(VclInputFlags nType) +{ + bool bResult = false; + if (nType & VclInputFlags::TIMER) + bResult |= (m_pTimer && m_pTimer->remainingTime() == 0); + if (nType & VclInputFlags::OTHER) + bResult |= !m_bSleeping; + return bResult; +} + +OUString QtInstance::GetConnectionIdentifier() { return OUString(); } + +void QtInstance::AddToRecentDocumentList(const OUString&, const OUString&, const OUString&) {} + +#ifndef EMSCRIPTEN +OpenGLContext* QtInstance::CreateOpenGLContext() { return new QtOpenGLContext; } +#endif + +bool QtInstance::IsMainThread() const +{ + return !qApp || (qApp->thread() == QThread::currentThread()); +} + +void QtInstance::TriggerUserEventProcessing() +{ + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); + dispatcher->wakeUp(); +} + +void QtInstance::ProcessEvent(SalUserEvent aEvent) +{ + aEvent.m_pFrame->CallCallback(aEvent.m_nEvent, aEvent.m_pData); +} + +rtl::Reference<QtFilePicker> +QtInstance::createPicker(css::uno::Reference<css::uno::XComponentContext> const& context, + QFileDialog::FileMode eMode) +{ + if (!IsMainThread()) + { + SolarMutexGuard g; + rtl::Reference<QtFilePicker> pPicker; + RunInMainThread([&, this]() { pPicker = createPicker(context, eMode); }); + assert(pPicker); + return pPicker; + } + + return new QtFilePicker(context, eMode); +} + +css::uno::Reference<css::ui::dialogs::XFilePicker2> +QtInstance::createFilePicker(const css::uno::Reference<css::uno::XComponentContext>& context) +{ + return css::uno::Reference<css::ui::dialogs::XFilePicker2>( + createPicker(context, QFileDialog::ExistingFile)); +} + +css::uno::Reference<css::ui::dialogs::XFolderPicker2> +QtInstance::createFolderPicker(const css::uno::Reference<css::uno::XComponentContext>& context) +{ + return css::uno::Reference<css::ui::dialogs::XFolderPicker2>( + createPicker(context, QFileDialog::Directory)); +} + +css::uno::Reference<css::uno::XInterface> +QtInstance::CreateClipboard(const css::uno::Sequence<css::uno::Any>& arguments) +{ + OUString sel; + if (arguments.getLength() == 0) + { + sel = "CLIPBOARD"; + } + else if (arguments.getLength() != 1 || !(arguments[0] >>= sel)) + { + throw css::lang::IllegalArgumentException("bad QtInstance::CreateClipboard arguments", + css::uno::Reference<css::uno::XInterface>(), -1); + } + + // This could also use RunInMain, but SolarMutexGuard is enough + // since at this point we're not accessing the clipboard, just get the + // accessor to the clipboard. + SolarMutexGuard aGuard; + + auto it = m_aClipboards.find(sel); + if (it != m_aClipboards.end()) + return it->second; + + css::uno::Reference<css::uno::XInterface> xClipboard = QtClipboard::create(sel); + if (xClipboard.is()) + m_aClipboards[sel] = xClipboard; + + return xClipboard; +} + +css::uno::Reference<css::uno::XInterface> QtInstance::CreateDragSource() +{ + return css::uno::Reference<css::uno::XInterface>( + static_cast<cppu::OWeakObject*>(new QtDragSource())); +} + +css::uno::Reference<css::uno::XInterface> QtInstance::CreateDropTarget() +{ + return css::uno::Reference<css::uno::XInterface>( + static_cast<cppu::OWeakObject*>(new QtDropTarget())); +} + +IMPL_LINK_NOARG(QtInstance, updateStyleHdl, Timer*, void) +{ + SolarMutexGuard aGuard; + SalFrame* pFrame = anyFrame(); + if (pFrame) + { + pFrame->CallCallback(SalEvent::SettingsChanged, nullptr); + if (m_bUpdateFonts) + { + pFrame->CallCallback(SalEvent::FontChanged, nullptr); + m_bUpdateFonts = false; + } + } +} + +void QtInstance::UpdateStyle(bool bFontsChanged) +{ + if (bFontsChanged) + m_bUpdateFonts = true; + if (!m_aUpdateStyleTimer.IsActive()) + m_aUpdateStyleTimer.Start(); +} + +void* QtInstance::CreateGStreamerSink(const SystemChildWindow* pWindow) +{ +#if ENABLE_GSTREAMER_1_0 && QT5_HAVE_GOBJECT + auto pSymbol = gstElementFactoryNameSymbol(); + if (!pSymbol) + return nullptr; + + const SystemEnvData* pEnvData = pWindow->GetSystemData(); + if (!pEnvData) + return nullptr; + + if (pEnvData->platform != SystemEnvData::Platform::Wayland) + return nullptr; + + GstElement* pVideosink = pSymbol("qwidget5videosink", "qwidget5videosink"); + if (pVideosink) + { + QWidget* pQWidget = static_cast<QWidget*>(pEnvData->pWidget); + g_object_set(G_OBJECT(pVideosink), "widget", pQWidget, nullptr); + } + else + { + SAL_WARN("vcl.qt5", "Couldn't initialize qwidget5videosink." + " Video playback might not work as expected." + " Please install Qt5 packages for QtGStreamer."); + // with no videosink explicitly set, GStreamer will open its own (misplaced) window(s) to display video + } + + return pVideosink; +#else + Q_UNUSED(pWindow); + return nullptr; +#endif +} + +void QtInstance::AllocFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, + std::unique_ptr<int>& rFakeArgc, + std::vector<FreeableCStr>& rFakeArgvFreeable) +{ + OString aVersion(qVersion()); + SAL_INFO("vcl.qt5", "qt version string is " << aVersion); + + const sal_uInt32 nParams = osl_getCommandArgCount(); + sal_uInt32 nDisplayValueIdx = 0; + OUString aParam, aBin; + + for (sal_uInt32 nIdx = 0; nIdx < nParams; ++nIdx) + { + osl_getCommandArg(nIdx, &aParam.pData); + if (aParam != "-display") + continue; + ++nIdx; + nDisplayValueIdx = nIdx; + } + + osl_getExecutableFile(&aParam.pData); + osl_getSystemPathFromFileURL(aParam.pData, &aBin.pData); + OString aExec = OUStringToOString(aBin, osl_getThreadTextEncoding()); + + std::vector<FreeableCStr> aFakeArgvFreeable; + aFakeArgvFreeable.reserve(4); + aFakeArgvFreeable.emplace_back(strdup(aExec.getStr())); + aFakeArgvFreeable.emplace_back(strdup("--nocrashhandler")); + if (nDisplayValueIdx) + { + aFakeArgvFreeable.emplace_back(strdup("-display")); + osl_getCommandArg(nDisplayValueIdx, &aParam.pData); + OString aDisplay = OUStringToOString(aParam, osl_getThreadTextEncoding()); + aFakeArgvFreeable.emplace_back(strdup(aDisplay.getStr())); + } + rFakeArgvFreeable.swap(aFakeArgvFreeable); + + const int nFakeArgc = rFakeArgvFreeable.size(); + rFakeArgv.reset(new char*[nFakeArgc]); + for (int i = 0; i < nFakeArgc; i++) + rFakeArgv[i] = rFakeArgvFreeable[i].get(); + + rFakeArgc.reset(new int); + *rFakeArgc = nFakeArgc; +} + +void QtInstance::MoveFakeCmdlineArgs(std::unique_ptr<char* []>& rFakeArgv, + std::unique_ptr<int>& rFakeArgc, + std::vector<FreeableCStr>& rFakeArgvFreeable) +{ + m_pFakeArgv = std::move(rFakeArgv); + m_pFakeArgc = std::move(rFakeArgc); + m_pFakeArgvFreeable.swap(rFakeArgvFreeable); +} + +std::unique_ptr<QApplication> QtInstance::CreateQApplication(int& nArgc, char** pArgv) +{ + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // for scaled icons in the native menus + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + + FreeableCStr session_manager; + if (getenv("SESSION_MANAGER") != nullptr) + { + session_manager.reset(strdup(getenv("SESSION_MANAGER"))); + unsetenv("SESSION_MANAGER"); + } + + std::unique_ptr<QApplication> pQApp = std::make_unique<QApplication>(nArgc, pArgv); + + if (session_manager != nullptr) + { + // coverity[tainted_string] - trusted source for setenv + setenv("SESSION_MANAGER", session_manager.get(), 1); + } + + QApplication::setQuitOnLastWindowClosed(false); + return pQApp; +} + +extern "C" { +VCLPLUG_QT5_PUBLIC SalInstance* create_SalInstance() +{ + static const bool bUseCairo = (nullptr != getenv("SAL_VCL_QT5_USE_CAIRO")); + + std::unique_ptr<char* []> pFakeArgv; + std::unique_ptr<int> pFakeArgc; + std::vector<FreeableCStr> aFakeArgvFreeable; + QtInstance::AllocFakeCmdlineArgs(pFakeArgv, pFakeArgc, aFakeArgvFreeable); + + std::unique_ptr<QApplication> pQApp + = QtInstance::CreateQApplication(*pFakeArgc, pFakeArgv.get()); + + QtInstance* pInstance = new QtInstance(pQApp, bUseCairo); + pInstance->MoveFakeCmdlineArgs(pFakeArgv, pFakeArgc, aFakeArgvFreeable); + + new QtData(pInstance); + + return pInstance; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtInstance_Print.cxx b/vcl/qt5/QtInstance_Print.cxx new file mode 100644 index 000000000000..30251c8bb003 --- /dev/null +++ b/vcl/qt5/QtInstance_Print.cxx @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <string_view> + +#include <QtInstance.hxx> +#include <QtPrinter.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/timer.hxx> +#include <vcl/QueueInfo.hxx> +#include <printerinfomanager.hxx> + +#include <jobset.h> +#include <print.h> +#include <salptype.hxx> +#include <saldatabasic.hxx> + +#include <unx/genpspgraphics.h> + +using namespace psp; + +/* + * static helpers + */ + +static OUString getPdfDir(const PrinterInfo& rInfo) +{ + OUString aDir; + sal_Int32 nIndex = 0; + while (nIndex != -1) + { + OUString aToken(rInfo.m_aFeatures.getToken(0, ',', nIndex)); + if (aToken.startsWith("pdf=")) + { + sal_Int32 nPos = 0; + aDir = aToken.getToken(1, '=', nPos); + if (aDir.isEmpty()) + if (auto const env = getenv("HOME")) + { + aDir = OStringToOUString(std::string_view(env), osl_getThreadTextEncoding()); + } + break; + } + } + return aDir; +} + +SalInfoPrinter* QtInstance::CreateInfoPrinter(SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pJobSetup) +{ + // create and initialize SalInfoPrinter + PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter; + configurePspInfoPrinter(pPrinter, pQueueInfo, pJobSetup); + + return pPrinter; +} + +void QtInstance::DestroyInfoPrinter(SalInfoPrinter* pPrinter) { delete pPrinter; } + +std::unique_ptr<SalPrinter> QtInstance::CreatePrinter(SalInfoPrinter* pInfoPrinter) +{ + // create and initialize SalPrinter + QtPrinter* pPrinter = new QtPrinter(pInfoPrinter); + pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData; + + return std::unique_ptr<SalPrinter>(pPrinter); +} + +void QtInstance::GetPrinterQueueInfo(ImplPrnQueueList* pList) +{ + PrinterInfoManager& rManager(PrinterInfoManager::get()); + static const char* pNoSyncDetection = getenv("SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION"); + if (!pNoSyncDetection || !*pNoSyncDetection) + { + // #i62663# synchronize possible asynchronouse printer detection now + rManager.checkPrintersChanged(true); + } + ::std::vector<OUString> aPrinters; + rManager.listPrinters(aPrinters); + + for (const auto& rPrinter : aPrinters) + { + const PrinterInfo& rInfo(rManager.getPrinterInfo(rPrinter)); + // create new entry + std::unique_ptr<SalPrinterQueueInfo> pInfo(new SalPrinterQueueInfo); + pInfo->maPrinterName = rPrinter; + pInfo->maDriver = rInfo.m_aDriverName; + pInfo->maLocation = rInfo.m_aLocation; + pInfo->maComment = rInfo.m_aComment; + + sal_Int32 nIndex = 0; + while (nIndex != -1) + { + OUString aToken(rInfo.m_aFeatures.getToken(0, ',', nIndex)); + if (aToken.startsWith("pdf=")) + { + pInfo->maLocation = getPdfDir(rInfo); + break; + } + } + + pList->Add(std::move(pInfo)); + } +} + +void QtInstance::GetPrinterQueueState(SalPrinterQueueInfo*) {} + +OUString QtInstance::GetDefaultPrinter() +{ + PrinterInfoManager& rManager(PrinterInfoManager::get()); + return rManager.getDefaultPrinter(); +} + +void QtInstance::PostPrintersChanged() {} + +std::unique_ptr<GenPspGraphics> QtInstance::CreatePrintGraphics() +{ + return std::make_unique<GenPspGraphics>(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtMainWindow.cxx b/vcl/qt5/QtMainWindow.cxx new file mode 100644 index 000000000000..1e6ebc81a7be --- /dev/null +++ b/vcl/qt5/QtMainWindow.cxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <QtMainWindow.hxx> +#include <QtMainWindow.moc> +#include <QtAccessibleWidget.hxx> + +#include <QtGui/QAccessible> +#include <QtGui/QCloseEvent> + +QtMainWindow::QtMainWindow(QtFrame& rFrame, Qt::WindowFlags f) + : QMainWindow(nullptr, f) + , m_rFrame(rFrame) +{ +#ifndef EMSCRIPTEN + QAccessible::installFactory(QtAccessibleWidget::customFactory); +#endif +} + +void QtMainWindow::closeEvent(QCloseEvent* pEvent) +{ + bool bRet = false; + bRet = m_rFrame.CallCallback(SalEvent::Close, nullptr); + + if (bRet) + pEvent->accept(); + // SalEvent::Close returning false may mean that user has vetoed + // closing the frame ("you have unsaved changes" dialog for example) + // We shouldn't process the event in such case + else + pEvent->ignore(); +} + +void QtMainWindow::moveEvent(QMoveEvent* pEvent) +{ + const qreal fRatio = m_rFrame.devicePixelRatioF(); + m_rFrame.maGeometry.nX = round(pEvent->pos().x() * fRatio); + m_rFrame.maGeometry.nY = round(pEvent->pos().y() * fRatio); + m_rFrame.CallCallback(SalEvent::Move, nullptr); +} diff --git a/vcl/qt5/QtMenu.cxx b/vcl/qt5/QtMenu.cxx new file mode 100644 index 000000000000..6ba35daa0429 --- /dev/null +++ b/vcl/qt5/QtMenu.cxx @@ -0,0 +1,702 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 <QtMenu.hxx> +#include <QtMenu.moc> + +#include <QtFrame.hxx> +#include <QtInstance.hxx> +#include <QtMainWindow.hxx> + +#include <QtWidgets/QMenuBar> +#include <QtWidgets/QPushButton> + +#include <o3tl/safeint.hxx> +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + +#include <strings.hrc> +#include <bitmaps.hlst> + +#include <vcl/toolkit/floatwin.hxx> +#include <window.h> + +QtMenu::QtMenu(bool bMenuBar) + : mpVCLMenu(nullptr) + , mpParentSalMenu(nullptr) + , mpFrame(nullptr) + , mbMenuBar(bMenuBar) + , mpQMenuBar(nullptr) + , mpQMenu(nullptr) + , mpCloseButton(nullptr) +{ +} + +bool QtMenu::VisibleMenuBar() { return true; } + +void QtMenu::InsertMenuItem(QtMenuItem* pSalMenuItem, unsigned nPos) +{ + sal_uInt16 nId = pSalMenuItem->mnId; + OUString aText = mpVCLMenu->GetItemText(nId); + NativeItemText(aText); + vcl::KeyCode nAccelKey = mpVCLMenu->GetAccelKey(nId); + + pSalMenuItem->mpAction.reset(); + pSalMenuItem->mpMenu.reset(); + + if (mbMenuBar) + { + // top-level menu + if (mpQMenuBar) + { + QMenu* pQMenu = new QMenu(toQString(aText), nullptr); + pSalMenuItem->mpMenu.reset(pQMenu); + + if ((nPos != MENU_APPEND) + && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenuBar->actions().size()))) + { + mpQMenuBar->insertMenu(mpQMenuBar->actions()[nPos], pQMenu); + } + else + { + mpQMenuBar->addMenu(pQMenu); + } + + // correct parent menu for generated menu + if (pSalMenuItem->mpSubMenu) + { + pSalMenuItem->mpSubMenu->mpQMenu = pQMenu; + } + + connect(pQMenu, &QMenu::aboutToShow, this, + [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); }); + connect(pQMenu, &QMenu::aboutToHide, this, + [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); }); + } + } + else + { + if (!mpQMenu) + { + // no QMenu set, instantiate own one + mpOwnedQMenu.reset(new QMenu); + mpQMenu = mpOwnedQMenu.get(); + } + + if (pSalMenuItem->mpSubMenu) + { + // submenu + QMenu* pQMenu = new QMenu(toQString(aText), nullptr); + pSalMenuItem->mpMenu.reset(pQMenu); + + if ((nPos != MENU_APPEND) + && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) + { + mpQMenu->insertMenu(mpQMenu->actions()[nPos], pQMenu); + } + else + { + mpQMenu->addMenu(pQMenu); + } + + // correct parent menu for generated menu + pSalMenuItem->mpSubMenu->mpQMenu = pQMenu; + + ReinitializeActionGroup(nPos); + + // clear all action groups since menu is recreated + pSalMenuItem->mpSubMenu->ResetAllActionGroups(); + + connect(pQMenu, &QMenu::aboutToShow, this, + [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); }); + connect(pQMenu, &QMenu::aboutToHide, this, + [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); }); + } + else + { + if (pSalMenuItem->mnType == MenuItemType::SEPARATOR) + { + QAction* pAction = new QAction(nullptr); + pSalMenuItem->mpAction.reset(pAction); + pAction->setSeparator(true); + + if ((nPos != MENU_APPEND) + && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) + { + mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction); + } + else + { + mpQMenu->addAction(pAction); + } + + ReinitializeActionGroup(nPos); + } + else + { + // leaf menu + QAction* pAction = new QAction(toQString(aText), nullptr); + pSalMenuItem->mpAction.reset(pAction); + + if ((nPos != MENU_APPEND) + && (static_cast<size_t>(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) + { + mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction); + } + else + { + mpQMenu->addAction(pAction); + } + + ReinitializeActionGroup(nPos); + + UpdateActionGroupItem(pSalMenuItem); + + pAction->setShortcut(toQString(nAccelKey.GetName())); + + connect(pAction, &QAction::triggered, this, + [pSalMenuItem] { slotMenuTriggered(pSalMenuItem); }); + } + } + } + + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + { + pAction->setEnabled(pSalMenuItem->mbEnabled); + pAction->setVisible(pSalMenuItem->mbVisible); + } +} + +void QtMenu::ReinitializeActionGroup(unsigned nPos) +{ + const unsigned nCount = GetItemCount(); + + if (nCount == 0) + { + return; + } + + if (nPos == MENU_APPEND) + { + nPos = nCount - 1; + } + else if (nPos >= nCount) + { + return; + } + + QtMenuItem* pPrevItem = (nPos > 0) ? GetItemAtPos(nPos - 1) : nullptr; + QtMenuItem* pCurrentItem = GetItemAtPos(nPos); + QtMenuItem* pNextItem = (nPos < nCount - 1) ? GetItemAtPos(nPos + 1) : nullptr; + + if (pCurrentItem->mnType == MenuItemType::SEPARATOR) + { + pCurrentItem->mpActionGroup.reset(); + + // if it's inserted into middle of existing group, split it into two groups: + // first goes original group, after separator goes new group + if (pPrevItem && pPrevItem->mpActionGroup && pNextItem && pNextItem->mpActionGroup + && (pPrevItem->mpActionGroup == pNextItem->mpActionGroup)) + { + std::shared_ptr<QActionGroup> pFirstActionGroup = pPrevItem->mpActionGroup; + auto pSecondActionGroup = std::make_shared<QActionGroup>(nullptr); + pSecondActionGroup->setExclusive(true); + + auto actions = pFirstActionGroup->actions(); + + for (unsigned idx = nPos + 1; idx < nCount; ++idx) + { + QtMenuItem* pModifiedItem = GetItemAtPos(idx); + + if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup)) + { + break; + } + + pModifiedItem->mpActionGroup = pSecondActionGroup; + auto action = pModifiedItem->getAction(); + + if (actions.contains(action)) + { + pFirstActionGroup->removeAction(action); + pSecondActionGroup->addAction(action); + } + } + } + } + else + { + if (!pCurrentItem->mpActionGroup) + { + // unless element is inserted between two separators, or a separator and an end of vector, use neighbouring group since it's shared + if (pPrevItem && pPrevItem->mpActionGroup) + { + pCurrentItem->mpActionGroup = pPrevItem->mpActionGroup; + } + else if (pNextItem && pNextItem->mpActionGroup) + { + pCurrentItem->mpActionGroup = pNextItem->mpActionGroup; + } + else + { + pCurrentItem->mpActionGroup = std::make_shared<QActionGroup>(nullptr); + pCurrentItem->mpActionGroup->setExclusive(true); + } + } + + // if there's also a different group after this element, merge it + if (pNextItem && pNextItem->mpActionGroup + && (pCurrentItem->mpActionGroup != pNextItem->mpActionGroup)) + { + auto pFirstCheckedAction = pCurrentItem->mpActionGroup->checkedAction(); + auto pSecondCheckedAction = pNextItem->mpActionGroup->checkedAction(); + auto actions = pNextItem->mpActionGroup->actions(); + + // first move all actions from second group to first one, and if first group already has checked action, + // and second group also has a checked action, uncheck action from second group + for (auto action : actions) + { + pNextItem->mpActionGroup->removeAction(action); + + if (pFirstCheckedAction && pSecondCheckedAction && (action == pSecondCheckedAction)) + { + action->setChecked(false); + } + + pCurrentItem->mpActionGroup->addAction(action); + } + + // now replace all pointers to second group with pointers to first group + for (unsigned idx = nPos + 1; idx < nCount; ++idx) + { + QtMenuItem* pModifiedItem = GetItemAtPos(idx); + + if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup)) + { + break; + } + + pModifiedItem->mpActionGroup = pCurrentItem->mpActionGroup; + } + } + } +} + +void QtMenu::ResetAllActionGroups() +{ + for (unsigned nItem = 0; nItem < GetItemCount(); ++nItem) + { + QtMenuItem* pSalMenuItem = GetItemAtPos(nItem); + pSalMenuItem->mpActionGroup.reset(); + } +} + +void QtMenu::UpdateActionGroupItem(const QtMenuItem* pSalMenuItem) +{ + QAction* pAction = pSalMenuItem->getAction(); + if (!pAction) + return; + + bool bChecked = mpVCLMenu->IsItemChecked(pSalMenuItem->mnId); + MenuItemBits itemBits = mpVCLMenu->GetItemBits(pSalMenuItem->mnId); + + if (itemBits & MenuItemBits::RADIOCHECK) + { + pAction->setCheckable(true); + + if (pSalMenuItem->mpActionGroup) + { + pSalMenuItem->mpActionGroup->addAction(pAction); + } + + pAction->setChecked(bChecked); + } + else + { + pAction->setActionGroup(nullptr); + + if (itemBits & MenuItemBits::CHECKABLE) + { + pAction->setCheckable(true); + pAction->setChecked(bChecked); + } + else + { + pAction->setChecked(false); + pAction->setCheckable(false); + } + } +} + +void QtMenu::InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos) +{ + SolarMutexGuard aGuard; + QtMenuItem* pItem = static_cast<QtMenuItem*>(pSalMenuItem); + + if (nPos == MENU_APPEND) + maItems.push_back(pItem); + else + maItems.insert(maItems.begin() + nPos, pItem); + + pItem->mpParentMenu = this; + + InsertMenuItem(pItem, nPos); +} + +void QtMenu::RemoveItem(unsigned nPos) +{ + SolarMutexGuard aGuard; + + if (nPos >= maItems.size()) + return; + + QtMenuItem* pItem = maItems[nPos]; + pItem->mpAction.reset(); + pItem->mpMenu.reset(); + + maItems.erase(maItems.begin() + nPos); + + // Recalculate action groups if necessary: + // if separator between two QActionGroups was removed, + // it may be needed to merge them + if (nPos > 0) + { + ReinitializeActionGroup(nPos - 1); + } +} + +void QtMenu::SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos) +{ + SolarMutexGuard aGuard; + QtMenuItem* pItem = static_cast<QtMenuItem*>(pSalMenuItem); + QtMenu* pQSubMenu = static_cast<QtMenu*>(pSubMenu); + + pItem->mpSubMenu = pQSubMenu; + // at this point the pointer to parent menu may be outdated, update it too + pItem->mpParentMenu = this; + + if (pQSubMenu != nullptr) + { + pQSubMenu->mpParentSalMenu = this; + pQSubMenu->mpQMenu = pItem->mpMenu.get(); + } + + // if it's not a menu bar item, then convert it to corresponding item if type if necessary. + // If submenu is present and it's an action, convert it to menu. + // If submenu is not present and it's a menu, convert it to action. + // It may be fine to proceed in any case, but by skipping other cases + // amount of unneeded actions taken should be reduced. + if (pItem->mpParentMenu->mbMenuBar || (pQSubMenu && pItem->mpMenu) + || ((!pQSubMenu) && pItem->mpAction)) + { + return; + } + + InsertMenuItem(pItem, nPos); +} + +void QtMenu::SetFrame(const SalFrame* pFrame) +{ + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, pFrame]() { SetFrame(pFrame); }); + return; + } + + SolarMutexGuard aGuard; + assert(mbMenuBar); + mpFrame = const_cast<QtFrame*>(static_cast<const QtFrame*>(pFrame)); + + mpFrame->SetMenu(this); + + QtMainWindow* pMainWindow = mpFrame->GetTopLevelWindow(); + if (!pMainWindow) + return; + + mpQMenuBar = pMainWindow->menuBar(); + if (mpQMenuBar) + { + mpQMenuBar->clear(); + QPushButton* pButton + = static_cast<QPushButton*>(mpQMenuBar->cornerWidget(Qt::TopRightCorner)); + if (pButton && ((mpCloseButton != pButton) || !maCloseButtonConnection)) + { + maCloseButtonConnection + = connect(pButton, &QPushButton::clicked, this, &QtMenu::slotCloseDocument); + mpCloseButton = pButton; + } + } + + mpQMenu = nullptr; + + DoFullMenuUpdate(mpVCLMenu); +} + +void QtMenu::DoFullMenuUpdate(Menu* pMenuBar) +{ + // clear action groups since menu is rebuilt + ResetAllActionGroups(); + ShowCloseButton(false); + + for (sal_Int32 nItem = 0; nItem < static_cast<sal_Int32>(GetItemCount()); nItem++) + { + QtMenuItem* pSalMenuItem = GetItemAtPos(nItem); + InsertMenuItem(pSalMenuItem, nItem); + SetItemImage(nItem, pSalMenuItem, pSalMenuItem->maImage); + const bool bShowDisabled + = bool(pMenuBar->GetMenuFlags() & MenuFlags::AlwaysShowDisabledEntries) + || !bool(pMenuBar->GetMenuFlags() & MenuFlags::HideDisabledEntries); + const bool bVisible = bShowDisabled || mpVCLMenu->IsItemEnabled(pSalMenuItem->mnId); + pSalMenuItem->getAction()->setVisible(bVisible); + + if (pSalMenuItem->mpSubMenu != nullptr) + { + pMenuBar->HandleMenuActivateEvent(pSalMenuItem->mpSubMenu->GetMenu()); + pSalMenuItem->mpSubMenu->DoFullMenuUpdate(pMenuBar); + pMenuBar->HandleMenuDeActivateEvent(pSalMenuItem->mpSubMenu->GetMenu()); + } + } +} + +void QtMenu::ShowItem(unsigned nPos, bool bShow) +{ + if (nPos < maItems.size()) + { + QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + pAction->setVisible(bShow); + pSalMenuItem->mbVisible = bShow; + } +} + +void QtMenu::SetItemBits(unsigned nPos, MenuItemBits) +{ + if (nPos < maItems.size()) + { + QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); + UpdateActionGroupItem(pSalMenuItem); + } +} + +void QtMenu::CheckItem(unsigned nPos, bool bChecked) +{ + if (nPos < maItems.size()) + { + QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + { + pAction->setCheckable(true); + pAction->setChecked(bChecked); + } + } +} + +void QtMenu::EnableItem(unsigned nPos, bool bEnable) +{ + if (nPos < maItems.size()) + { + QtMenuItem* pSalMenuItem = GetItemAtPos(nPos); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + pAction->setEnabled(bEnable); + pSalMenuItem->mbEnabled = bEnable; + } +} + +void QtMenu::SetItemText(unsigned, SalMenuItem* pItem, const OUString& rText) +{ + QtMenuItem* pSalMenuItem = static_cast<QtMenuItem*>(pItem); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + { + OUString aText(rText); + NativeItemText(aText); + pAction->setText(toQString(aText)); + } +} + +void QtMenu::SetItemImage(unsigned, SalMenuItem* pItem, const Image& rImage) +{ + QtMenuItem* pSalMenuItem = static_cast<QtMenuItem*>(pItem); + + // Save new image to use it in DoFullMenuUpdate + pSalMenuItem->maImage = rImage; + + QAction* pAction = pSalMenuItem->getAction(); + if (!pAction) + return; + + pAction->setIcon(QPixmap::fromImage(toQImage(rImage))); +} + +void QtMenu::SetAccelerator(unsigned, SalMenuItem* pItem, const vcl::KeyCode&, + const OUString& rText) +{ + QtMenuItem* pSalMenuItem = static_cast<QtMenuItem*>(pItem); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + pAction->setShortcut(QKeySequence(toQString(rText), QKeySequence::PortableText)); +} + +void QtMenu::GetSystemMenuData(SystemMenuData*) {} + +QtMenu* QtMenu::GetTopLevel() +{ + QtMenu* pMenu = this; + while (pMenu->mpParentSalMenu) + pMenu = pMenu->mpParentSalMenu; + return pMenu; +} + +void QtMenu::ShowMenuBar(bool bVisible) +{ + if (mpQMenuBar) + mpQMenuBar->setVisible(bVisible); +} + +const QtFrame* QtMenu::GetFrame() const +{ + SolarMutexGuard aGuard; + const QtMenu* pMenu = this; + while (pMenu && !pMenu->mpFrame) + pMenu = pMenu->mpParentSalMenu; + return pMenu ? pMenu->mpFrame : nullptr; +} + +void QtMenu::slotMenuTriggered(QtMenuItem* pQItem) +{ + if (!pQItem) + return; + + QtMenu* pSalMenu = pQItem->mpParentMenu; + QtMenu* pTopLevel = pSalMenu->GetTopLevel(); + + Menu* pMenu = pSalMenu->GetMenu(); + auto mnId = pQItem->mnId; + + // HACK to allow HandleMenuCommandEvent to "not-set" the checked button + // LO expects a signal before an item state change, so reset the check item + if (pQItem->mpAction->isCheckable() + && (!pQItem->mpActionGroup || pQItem->mpActionGroup->actions().size() <= 1)) + pQItem->mpAction->setChecked(!pQItem->mpAction->isChecked()); + pTopLevel->GetMenu()->HandleMenuCommandEvent(pMenu, mnId); +} + +void QtMenu::slotMenuAboutToShow(QtMenuItem* pQItem) +{ + if (pQItem) + { + QtMenu* pSalMenu = pQItem->mpSubMenu; + QtMenu* pTopLevel = pSalMenu->GetTopLevel(); + + Menu* pMenu = pSalMenu->GetMenu(); + + // following function may update the menu + pTopLevel->GetMenu()->HandleMenuActivateEvent(pMenu); + } +} + +void QtMenu::slotMenuAboutToHide(QtMenuItem* pQItem) +{ + if (pQItem) + { + QtMenu* pSalMenu = pQItem->mpSubMenu; + QtMenu* pTopLevel = pSalMenu->GetTopLevel(); + + Menu* pMenu = pSalMenu->GetMenu(); + + pTopLevel->GetMenu()->HandleMenuDeActivateEvent(pMenu); + } +} + +void QtMenu::NativeItemText(OUString& rItemText) +{ + // preserve literal '&'s in menu texts + rItemText = rItemText.replaceAll("&", "&&"); + + rItemText = rItemText.replace('~', '&'); +} + +void QtMenu::slotCloseDocument() +{ + MenuBar* pVclMenuBar = static_cast<MenuBar*>(mpVCLMenu.get()); + if (pVclMenuBar) + Application::PostUserEvent(pVclMenuBar->GetCloseButtonClickHdl()); +} + +void QtMenu::ShowCloseButton(bool bShow) +{ + if (!mpQMenuBar) + return; + + QPushButton* pButton = static_cast<QPushButton*>(mpQMenuBar->cornerWidget(Qt::TopRightCorner)); + if (!pButton) + { + QIcon aIcon; + if (QIcon::hasThemeIcon("window-close-symbolic")) + aIcon = QIcon::fromTheme("window-close-symbolic"); + else + aIcon = QIcon( + QPixmap::fromImage(toQImage(Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC)))); + pButton = new QPushButton(mpQMenuBar); + pButton->setIcon(aIcon); + pButton->setFlat(true); + pButton->setFocusPolicy(Qt::NoFocus); + pButton->setToolTip(toQString(VclResId(SV_HELPTEXT_CLOSEDOCUMENT))); + mpQMenuBar->setCornerWidget(pButton, Qt::TopRightCorner); + maCloseButtonConnection + = connect(pButton, &QPushButton::clicked, this, &QtMenu::slotCloseDocument); + mpCloseButton = pButton; + } + + if (bShow) + pButton->show(); + else + pButton->hide(); +} + +bool QtMenu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&, + FloatWinPopupFlags nFlags) +{ + assert(mpQMenu); + DoFullMenuUpdate(mpVCLMenu); + mpQMenu->setTearOffEnabled(bool(nFlags & FloatWinPopupFlags::AllowTearOff)); + + const QPoint aPos = QCursor::pos(); + mpQMenu->exec(aPos); + + return true; +} + +QtMenuItem::QtMenuItem(const SalItemParams* pItemData) + : mpParentMenu(nullptr) + , mpSubMenu(nullptr) + , mnId(pItemData->nId) + , mnType(pItemData->eType) + , mbVisible(true) + , mbEnabled(true) + , maImage(pItemData->aImage) +{ +} + +QAction* QtMenuItem::getAction() const +{ + if (mpMenu) + return mpMenu->menuAction(); + if (mpAction) + return mpAction.get(); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtObject.cxx b/vcl/qt5/QtObject.cxx new file mode 100644 index 000000000000..1c9bc8d1fe09 --- /dev/null +++ b/vcl/qt5/QtObject.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 <QtObject.hxx> +#include <QtObject.moc> + +#include <QtFrame.hxx> +#include <QtWidget.hxx> + +#include <QtGui/QGuiApplication> + +QtObject::QtObject(QtFrame* pParent, bool bShow) + : m_pParent(pParent) + , m_pQWidget(nullptr) + , m_pQWindow(nullptr) +{ + if (!m_pParent || !pParent->GetQWidget()) + return; + + m_pQWindow = new QtObjectWindow(*this); + m_pQWidget = QWidget::createWindowContainer(m_pQWindow, pParent->GetQWidget()); + m_pQWidget->setAttribute(Qt::WA_NoSystemBackground); + connect(m_pQWidget, &QObject::destroyed, this, [this]() { m_pQWidget = nullptr; }); + + if (bShow) + m_pQWidget->show(); + + m_aSystemData.aShellWindow = reinterpret_cast<sal_IntPtr>(this); + //m_aSystemData.pSalFrame = this; + m_aSystemData.pWidget = m_pQWidget; + //m_aSystemData.nScreen = m_nXScreen.getXScreen(); + m_aSystemData.toolkit = SystemEnvData::Toolkit::Qt5; + m_aSystemData.platform = SystemEnvData::Platform::Xcb; + const bool bWayland = QGuiApplication::platformName() == "wayland"; + if (!bWayland) + { + m_aSystemData.platform = SystemEnvData::Platform::Xcb; + m_aSystemData.SetWindowHandle(m_pQWindow->winId()); // ID of the embedded window + } + else + { + m_aSystemData.platform = SystemEnvData::Platform::Wayland; + // TODO implement as needed for Wayland, + // s.a. commit c0d4f3ad3307c which did this for gtk3 + // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface(); + // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr); + // m_aSystemData.aWindow = reinterpret_cast<unsigned long>( + // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle())); + } +} + +QtObject::~QtObject() +{ + if (m_pQWidget) + { + m_pQWidget->setParent(nullptr); + delete m_pQWidget; + } +} + +void QtObject::ResetClipRegion() +{ + if (m_pQWidget) + m_pRegion = QRegion(m_pQWidget->geometry()); + else + m_pRegion = QRegion(); +} + +void QtObject::BeginSetClipRegion(sal_uInt32) { m_pRegion = QRegion(); } + +void QtObject::UnionClipRegion(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) +{ + m_pRegion += QRect(nX, nY, nWidth, nHeight); +} + +void QtObject::EndSetClipRegion() +{ + if (m_pQWidget) + m_pRegion = m_pRegion.intersected(m_pQWidget->geometry()); +} + +void QtObject::SetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight) +{ + if (m_pQWidget) + { + m_pQWidget->move(nX, nY); + m_pQWidget->setFixedSize(nWidth, nHeight); + } +} + +void QtObject::Show(bool bVisible) +{ + if (m_pQWidget) + m_pQWidget->setVisible(bVisible); +} + +void QtObject::SetForwardKey(bool /*bEnable*/) {} + +QtObjectWindow::QtObjectWindow(QtObject& rParent) + : m_rParent(rParent) +{ + assert(m_rParent.frame() && m_rParent.frame()->GetQWidget()); +} + +void QtObjectWindow::focusInEvent(QFocusEvent* pEvent) +{ + m_rParent.CallCallback(SalObjEvent::GetFocus); + QWindow::focusInEvent(pEvent); +} + +void QtObjectWindow::focusOutEvent(QFocusEvent* pEvent) +{ + m_rParent.CallCallback(SalObjEvent::LoseFocus); + QWindow::focusOutEvent(pEvent); +} + +void QtObjectWindow::mousePressEvent(QMouseEvent* pEvent) +{ + m_rParent.CallCallback(SalObjEvent::ToTop); + QtWidget::handleMousePressEvent(*m_rParent.frame(), pEvent); +} + +void QtObjectWindow::mouseReleaseEvent(QMouseEvent* pEvent) +{ + QtWidget::handleMouseReleaseEvent(*m_rParent.frame(), pEvent); +} + +bool QtObjectWindow::event(QEvent* pEvent) +{ + return QtWidget::handleEvent(*m_rParent.frame(), *m_rParent.widget(), pEvent) + || QWindow::event(pEvent); +} + +void QtObjectWindow::keyReleaseEvent(QKeyEvent* pEvent) +{ + if (!QtWidget::handleKeyReleaseEvent(*m_rParent.frame(), *m_rParent.widget(), pEvent)) + QWindow::keyReleaseEvent(pEvent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtOpenGLContext.cxx b/vcl/qt5/QtOpenGLContext.cxx new file mode 100644 index 000000000000..ab2e228f1dcc --- /dev/null +++ b/vcl/qt5/QtOpenGLContext.cxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtOpenGLContext.hxx> + +#include <epoxy/gl.h> + +#include <vcl/sysdata.hxx> +#include <opengl/zone.hxx> +#include <sal/log.hxx> + +#include <window.h> + +#include <QtObject.hxx> + +#include <QtGui/QOpenGLContext> +#include <QtGui/QWindow> + +bool QtOpenGLContext::g_bAnyCurrent = false; + +void QtOpenGLContext::swapBuffers() +{ + OpenGLZone aZone; + + if (m_pContext && m_pWindow && m_pWindow->isExposed()) + { + m_pContext->swapBuffers(m_pWindow); + } + + BuffersSwapped(); +} + +void QtOpenGLContext::resetCurrent() +{ + clearCurrent(); + + OpenGLZone aZone; + + if (m_pContext) + { + m_pContext->doneCurrent(); + g_bAnyCurrent = false; + } +} + +bool QtOpenGLContext::isCurrent() +{ + OpenGLZone aZone; + return g_bAnyCurrent && (QOpenGLContext::currentContext() == m_pContext); +} + +bool QtOpenGLContext::isAnyCurrent() +{ + OpenGLZone aZone; + return g_bAnyCurrent && (QOpenGLContext::currentContext() != nullptr); +} + +bool QtOpenGLContext::ImplInit() +{ + if (!m_pWindow) + { + SAL_WARN("vcl.opengl.qt5", "failed to create window"); + return false; + } + + m_pWindow->setSurfaceType(QSurface::OpenGLSurface); + m_pWindow->create(); + + m_pContext = new QOpenGLContext(m_pWindow); + if (!m_pContext->create()) + { + SAL_WARN("vcl.opengl.qt5", "failed to create context"); + return false; + } + + m_pContext->makeCurrent(m_pWindow); + g_bAnyCurrent = true; + + bool bRet = InitGL(); + InitGLDebugging(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + registerAsCurrent(); + + return bRet; +} + +void QtOpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + + if (m_pContext && m_pWindow) + { + m_pContext->makeCurrent(m_pWindow); + g_bAnyCurrent = true; + } + + registerAsCurrent(); +} + +void QtOpenGLContext::destroyCurrentContext() +{ + OpenGLZone aZone; + + if (m_pContext) + { + m_pContext->doneCurrent(); + g_bAnyCurrent = false; + } + + if (glGetError() != GL_NO_ERROR) + { + SAL_WARN("vcl.opengl.qt5", "glError: " << glGetError()); + } +} + +void QtOpenGLContext::initWindow() +{ + if (!m_pChildWindow) + { + SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); + m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false); + } + + if (m_pChildWindow) + { + InitChildWindow(m_pChildWindow.get()); + } + + m_pWindow + = static_cast<QtObject*>(m_pChildWindow->ImplGetWindowImpl()->mpSysObj)->windowHandle(); +} diff --git a/vcl/qt5/QtPainter.cxx b/vcl/qt5/QtPainter.cxx new file mode 100644 index 000000000000..fdf2a4ec08d7 --- /dev/null +++ b/vcl/qt5/QtPainter.cxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtPainter.hxx> + +#include <QtGui/QColor> + +QtPainter::QtPainter(QtGraphicsBackend& rGraphics, bool bPrepareBrush, sal_uInt8 nTransparency) + : m_rGraphics(rGraphics) +{ + if (rGraphics.m_pQImage) + { + if (!begin(rGraphics.m_pQImage)) + std::abort(); + } + else + { + assert(rGraphics.m_pFrame); + if (!begin(rGraphics.m_pFrame->GetQWidget())) + std::abort(); + } + if (!rGraphics.m_aClipPath.isEmpty()) + setClipPath(rGraphics.m_aClipPath); + else + setClipRegion(rGraphics.m_aClipRegion); + if (SALCOLOR_NONE != rGraphics.m_aLineColor) + { + QColor aColor = toQColor(rGraphics.m_aLineColor); + aColor.setAlpha(nTransparency); + setPen(aColor); + } + else + setPen(Qt::NoPen); + if (bPrepareBrush && SALCOLOR_NONE != rGraphics.m_aFillColor) + { + QColor aColor = toQColor(rGraphics.m_aFillColor); + aColor.setAlpha(nTransparency); + setBrush(aColor); + } + setCompositionMode(rGraphics.m_eCompositionMode); +} diff --git a/vcl/qt5/QtPrinter.cxx b/vcl/qt5/QtPrinter.cxx new file mode 100644 index 000000000000..346dd3f26e3f --- /dev/null +++ b/vcl/qt5/QtPrinter.cxx @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtPrinter.hxx> + +QtPrinter::QtPrinter(SalInfoPrinter* pInfoPrinter) + : PspSalPrinter(pInfoPrinter) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtSvpGraphics.cxx b/vcl/qt5/QtSvpGraphics.cxx new file mode 100644 index 000000000000..b6018a95e299 --- /dev/null +++ b/vcl/qt5/QtSvpGraphics.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/. + */ + +#include <sal/config.h> +#include <sal/log.hxx> +#include <salbmp.hxx> + +#include <config_cairo_canvas.h> + +#include <QtData.hxx> +#include <QtFrame.hxx> +#include <QtGraphics_Controls.hxx> +#include <QtSvpGraphics.hxx> +#include <QtSvpSurface.hxx> +#include <QtTools.hxx> + +#include <QtGui/QScreen> +#include <QtGui/QWindow> +#include <QtWidgets/QWidget> + +QtSvpGraphics::QtSvpGraphics(QtFrame* pFrame) + : m_pFrame(pFrame) +{ + if (!QtData::noNativeControls()) + m_pWidgetDraw.reset(new QtGraphics_Controls(*this)); + if (m_pFrame) + setDevicePixelRatioF(m_pFrame->devicePixelRatioF()); +} + +QtSvpGraphics::~QtSvpGraphics() {} + +void QtSvpGraphics::updateQWidget() const +{ + if (!m_pFrame) + return; + QWidget* pQWidget = m_pFrame->GetQWidget(); + if (pQWidget) + pQWidget->update(pQWidget->rect()); +} + +#if ENABLE_CAIRO_CANVAS + +bool QtSvpGraphics::SupportsCairo() const { return true; } + +cairo::SurfaceSharedPtr +QtSvpGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const +{ + return std::make_shared<cairo::QtSvpSurface>(rSurface); +} + +cairo::SurfaceSharedPtr QtSvpGraphics::CreateSurface(const OutputDevice& /*rRefDevice*/, int x, + int y, int width, int height) const +{ + return std::make_shared<cairo::QtSvpSurface>(this, x, y, width, height); +} + +#endif + +static void QImage2BitmapBuffer(QImage& rImg, BitmapBuffer& rBuf) +{ + assert(rImg.width()); + assert(rImg.height()); + + rBuf.mnWidth = rImg.width(); + rBuf.mnHeight = rImg.height(); + rBuf.mnBitCount = getFormatBits(rImg.format()); + rBuf.mpBits = rImg.bits(); + rBuf.mnScanlineSize = rImg.bytesPerLine(); +} + +void QtSvpGraphics::handleDamage(const tools::Rectangle& rDamagedRegion) +{ + assert(m_pWidgetDraw); + assert(dynamic_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())); + assert(!rDamagedRegion.IsEmpty()); + + QImage* pImage = static_cast<QtGraphics_Controls*>(m_pWidgetDraw.get())->getImage(); + assert(pImage); + if (pImage->width() == 0 || pImage->height() == 0) + return; + + BitmapBuffer aBuffer; + QImage2BitmapBuffer(*pImage, aBuffer); + SalTwoRect aTR(0, 0, pImage->width(), pImage->height(), rDamagedRegion.Left(), + rDamagedRegion.Top(), rDamagedRegion.GetWidth(), rDamagedRegion.GetHeight()); + drawBitmap(aTR, &aBuffer, CAIRO_OPERATOR_OVER); +} + +void QtSvpGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) +{ + char* pForceDpi; + if ((pForceDpi = getenv("SAL_FORCEDPI"))) + { + OString sForceDPI(pForceDpi); + rDPIX = rDPIY = sForceDPI.toInt32(); + return; + } + + if (!m_pFrame || !m_pFrame->GetQWidget()->window()->windowHandle()) + return; + + QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen(); + rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5; + rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtSvpSurface.cxx b/vcl/qt5/QtSvpSurface.cxx new file mode 100644 index 000000000000..456de177ce2c --- /dev/null +++ b/vcl/qt5/QtSvpSurface.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <utility> + +#include <QtSvpSurface.hxx> + +#include <QtSvpGraphics.hxx> + +#include <vcl/sysdata.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/virdev.hxx> +#include <vcl/window.hxx> +#include <basegfx/vector/b2isize.hxx> + +namespace +{ +Size get_surface_size(cairo_surface_t* surface) +{ + cairo_t* cr = cairo_create(surface); + double x1, x2, y1, y2; + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + cairo_destroy(cr); + return Size(x2 - x1, y2 - y1); +} +} + +namespace cairo +{ +QtSvpSurface::QtSvpSurface(const CairoSurfaceSharedPtr& pSurface) + : m_pGraphics(nullptr) + , m_pCairoContext(nullptr) + , m_pSurface(pSurface) +{ +} + +QtSvpSurface::QtSvpSurface(const QtSvpGraphics* pGraphics, int x, int y, int width, int height) + : m_pGraphics(pGraphics) + , m_pCairoContext(pGraphics->getCairoContext(false)) +{ + cairo_surface_t* surface = cairo_get_target(m_pCairoContext); + m_pSurface.reset(cairo_surface_create_for_rectangle(surface, x, y, width, height), + &cairo_surface_destroy); +} + +QtSvpSurface::~QtSvpSurface() +{ + if (m_pCairoContext) + cairo_destroy(m_pCairoContext); +} + +CairoSharedPtr QtSvpSurface::getCairo() const +{ + return CairoSharedPtr(cairo_create(m_pSurface.get()), &cairo_destroy); +} + +SurfaceSharedPtr QtSvpSurface::getSimilar(int cairo_content_type, int width, int height) const +{ + return std::make_shared<QtSvpSurface>(CairoSurfaceSharedPtr( + cairo_surface_create_similar( + m_pSurface.get(), static_cast<cairo_content_t>(cairo_content_type), width, height), + &cairo_surface_destroy)); +} + +void QtSvpSurface::flush() const +{ + cairo_surface_flush(m_pSurface.get()); + if (m_pGraphics) + m_pGraphics->updateQWidget(); +} + +VclPtr<VirtualDevice> QtSvpSurface::createVirtualDevice() const +{ + SystemGraphicsData aSystemGraphicsData; + + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.pSurface = m_pSurface.get(); + + return VclPtr<VirtualDevice>::Create(aSystemGraphicsData, get_surface_size(m_pSurface.get()), + DeviceFormat::DEFAULT); +} + +} // namespace cairo + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtSvpVirtualDevice.hxx b/vcl/qt5/QtSvpVirtualDevice.hxx new file mode 100644 index 000000000000..26247a6e1d58 --- /dev/null +++ b/vcl/qt5/QtSvpVirtualDevice.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <headless/svpvd.hxx> +#include <QtSvpGraphics.hxx> + +class VCL_DLLPUBLIC QtSvpVirtualDevice : public SvpSalVirtualDevice +{ +public: + QtSvpVirtualDevice(cairo_surface_t* pRefSurface, cairo_surface_t* pPreExistingTarget) + : SvpSalVirtualDevice(pRefSurface, pPreExistingTarget) + { + } + + SalGraphics* AcquireGraphics() override { return AddGraphics(new QtSvpGraphics(nullptr)); } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtSystem.cxx b/vcl/qt5/QtSystem.cxx new file mode 100644 index 000000000000..5f5f4ad284e5 --- /dev/null +++ b/vcl/qt5/QtSystem.cxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> + +#include <tools/gen.hxx> +#include <QtSystem.hxx> +#include <QtTools.hxx> + +unsigned int QtSystem::GetDisplayScreenCount() { return QGuiApplication::screens().size(); } + +tools::Rectangle QtSystem::GetDisplayScreenPosSizePixel(unsigned int nScreen) +{ + QRect qRect = QGuiApplication::screens().at(nScreen)->geometry(); + return toRectangle(scaledQRect(qRect, qApp->devicePixelRatio())); +} + +int QtSystem::ShowNativeDialog(const OUString&, const OUString&, const std::vector<OUString>&) +{ + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtTimer.cxx b/vcl/qt5/QtTimer.cxx new file mode 100644 index 000000000000..751937b44931 --- /dev/null +++ b/vcl/qt5/QtTimer.cxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtTimer.hxx> +#include <QtTimer.moc> + +#include <QtWidgets/QApplication> +#include <QtCore/QThread> + +#include <vcl/svapp.hxx> +#include <sal/log.hxx> + +QtTimer::QtTimer() +{ + m_aTimer.setSingleShot(true); + m_aTimer.setTimerType(Qt::PreciseTimer); + connect(&m_aTimer, SIGNAL(timeout()), this, SLOT(timeoutActivated())); + connect(this, SIGNAL(startTimerSignal(int)), this, SLOT(startTimer(int))); + connect(this, SIGNAL(stopTimerSignal()), this, SLOT(stopTimer())); +} + +void QtTimer::timeoutActivated() +{ + SolarMutexGuard aGuard; + CallCallback(); +} + +void QtTimer::startTimer(int nMS) { m_aTimer.start(nMS); } + +void QtTimer::Start(sal_uInt64 nMS) { Q_EMIT startTimerSignal(nMS); } + +void QtTimer::stopTimer() { m_aTimer.stop(); } + +void QtTimer::Stop() { Q_EMIT stopTimerSignal(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtTools.cxx b/vcl/qt5/QtTools.cxx new file mode 100644 index 000000000000..f9a0a0e0e328 --- /dev/null +++ b/vcl/qt5/QtTools.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtTools.hxx> + +#include <cairo.h> + +#include <tools/stream.hxx> +#include <vcl/event.hxx> +#include <vcl/image.hxx> +#include <vcl/pngwrite.hxx> + +#include <QtGui/QImage> + +void CairoDeleter::operator()(cairo_surface_t* pSurface) const { cairo_surface_destroy(pSurface); } + +sal_uInt16 GetKeyModCode(Qt::KeyboardModifiers eKeyModifiers) +{ + sal_uInt16 nCode = 0; + if (eKeyModifiers & Qt::ShiftModifier) + nCode |= KEY_SHIFT; + if (eKeyModifiers & Qt::ControlModifier) + nCode |= KEY_MOD1; + if (eKeyModifiers & Qt::AltModifier) + nCode |= KEY_MOD2; + if (eKeyModifiers & Qt::MetaModifier) + nCode |= KEY_MOD3; + return nCode; +} + +sal_uInt16 GetMouseModCode(Qt::MouseButtons eButtons) +{ + sal_uInt16 nCode = 0; + if (eButtons & Qt::LeftButton) + nCode |= MOUSE_LEFT; + if (eButtons & Qt::MiddleButton) + nCode |= MOUSE_MIDDLE; + if (eButtons & Qt::RightButton) + nCode |= MOUSE_RIGHT; + return nCode; +} + +Qt::DropActions toQtDropActions(sal_Int8 dragOperation) +{ + Qt::DropActions eRet = Qt::IgnoreAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) + eRet |= Qt::CopyAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) + eRet |= Qt::MoveAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) + eRet |= Qt::LinkAction; + return eRet; +} + +sal_Int8 toVclDropActions(Qt::DropActions dragOperation) +{ + sal_Int8 nRet(0); + if (dragOperation & Qt::CopyAction) + nRet |= css::datatransfer::dnd::DNDConstants::ACTION_COPY; + if (dragOperation & Qt::MoveAction) + nRet |= css::datatransfer::dnd::DNDConstants::ACTION_MOVE; + if (dragOperation & Qt::LinkAction) + nRet |= css::datatransfer::dnd::DNDConstants::ACTION_LINK; + return nRet; +} + +sal_Int8 toVclDropAction(Qt::DropAction dragOperation) +{ + sal_Int8 nRet(0); + if (dragOperation == Qt::CopyAction) + nRet = css::datatransfer::dnd::DNDConstants::ACTION_COPY; + else if (dragOperation == Qt::MoveAction) + nRet = css::datatransfer::dnd::DNDConstants::ACTION_MOVE; + else if (dragOperation == Qt::LinkAction) + nRet = css::datatransfer::dnd::DNDConstants::ACTION_LINK; + return nRet; +} + +Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation) +{ + Qt::DropAction eAct = Qt::IgnoreAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) + eAct = Qt::MoveAction; + else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) + eAct = Qt::CopyAction; + else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) + eAct = Qt::LinkAction; + return eAct; +} + +QImage toQImage(const Image& rImage) +{ + QImage aImage; + + if (!!rImage) + { + SvMemoryStream aMemStm; + vcl::PNGWriter aWriter(rImage.GetBitmapEx()); + aWriter.Write(aMemStm); + aImage.loadFromData(static_cast<const uchar*>(aMemStm.GetData()), aMemStm.TellEnd()); + } + + return aImage; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtTransferable.cxx b/vcl/qt5/QtTransferable.cxx new file mode 100644 index 000000000000..cf92f57ab47b --- /dev/null +++ b/vcl/qt5/QtTransferable.cxx @@ -0,0 +1,344 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <QtTransferable.hxx> + +#include <comphelper/sequence.hxx> +#include <sal/log.hxx> + +#include <QtWidgets/QApplication> + +#include <QtInstance.hxx> +#include <QtTools.hxx> + +#include <cassert> + +static bool lcl_textMimeInfo(const OUString& rMimeString, bool& bHaveNoCharset, bool& bHaveUTF16, + bool& bHaveUTF8) +{ + sal_Int32 nIndex = 0; + if (rMimeString.getToken(0, ';', nIndex) == "text/plain") + { + OUString aToken(rMimeString.getToken(0, ';', nIndex)); + if (aToken == "charset=utf-16") + bHaveUTF16 = true; + else if (aToken == "charset=utf-8") + bHaveUTF8 = true; + else if (aToken.isEmpty()) + bHaveNoCharset = true; + else // we just handle UTF-16 and UTF-8, everything else is "bytes" + return false; + return true; + } + return false; +} + +QtTransferable::QtTransferable(const QMimeData* pMimeData) + : m_pMimeData(pMimeData) + , m_bConvertFromLocale(false) +{ + assert(pMimeData); +} + +css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL QtTransferable::getTransferDataFlavors() +{ + // it's just filled once, ever, so just try to get it without locking first + if (m_aMimeTypeSeq.hasElements()) + return m_aMimeTypeSeq; + + // better safe then sorry; preventing broken usage + // DnD should not be shared and Clipboard access runs in the GUI thread + osl::MutexGuard aGuard(m_aMutex); + if (m_aMimeTypeSeq.hasElements()) + return m_aMimeTypeSeq; + + QStringList aFormatList(m_pMimeData->formats()); + // we might add the UTF-16 mime text variant later + const int nMimeTypeSeqSize = aFormatList.size() + 1; + bool bHaveNoCharset = false, bHaveUTF16 = false; + css::uno::Sequence<css::datatransfer::DataFlavor> aMimeTypeSeq(nMimeTypeSeqSize); + + css::datatransfer::DataFlavor aFlavor; + int nMimeTypeCount = 0; + + for (const QString& rMimeType : aFormatList) + { + // filter out non-MIME types such as TARGETS, MULTIPLE, TIMESTAMP + if (rMimeType.indexOf('/') == -1) + continue; + + // gtk3 thinks it is not well defined - skip too + if (rMimeType == QStringLiteral("text/plain;charset=unicode")) + continue; + + // LO doesn't like 'text/plain', so we have to provide UTF-16 + bool bIsNoCharset = false, bIsUTF16 = false, bIsUTF8 = false; + if (lcl_textMimeInfo(toOUString(rMimeType), bIsNoCharset, bIsUTF16, bIsUTF8)) + { + bHaveNoCharset |= bIsNoCharset; + bHaveUTF16 |= bIsUTF16; + if (bIsUTF16) + aFlavor.DataType = cppu::UnoType<OUString>::get(); + else + aFlavor.DataType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(); + } + else + aFlavor.DataType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(); + + aFlavor.MimeType = toOUString(rMimeType); + assert(nMimeTypeCount < nMimeTypeSeqSize); + aMimeTypeSeq[nMimeTypeCount] = aFlavor; + nMimeTypeCount++; + } + + m_bConvertFromLocale = bHaveNoCharset && !bHaveUTF16; + if (m_bConvertFromLocale) + { + aFlavor.MimeType = "text/plain;charset=utf-16"; + aFlavor.DataType = cppu::UnoType<OUString>::get(); + assert(nMimeTypeCount < nMimeTypeSeqSize); + aMimeTypeSeq[nMimeTypeCount] = aFlavor; + nMimeTypeCount++; + } + + aMimeTypeSeq.realloc(nMimeTypeCount); + + m_aMimeTypeSeq = aMimeTypeSeq; + return m_aMimeTypeSeq; +} + +sal_Bool SAL_CALL +QtTransferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) +{ + const auto aSeq = getTransferDataFlavors(); + return std::any_of(aSeq.begin(), aSeq.end(), [&](const css::datatransfer::DataFlavor& aFlavor) { + return rFlavor.MimeType == aFlavor.MimeType; + }); +} + +css::uno::Any SAL_CALL QtTransferable::getTransferData(const css::datatransfer::DataFlavor& rFlavor) +{ + css::uno::Any aAny; + if (!isDataFlavorSupported(rFlavor)) + return aAny; + + if (rFlavor.MimeType == "text/plain;charset=utf-16") + { + OUString aString; + if (m_bConvertFromLocale) + { + QByteArray aByteData(m_pMimeData->data(QStringLiteral("text/plain"))); + aString = OUString(reinterpret_cast<const char*>(aByteData.data()), aByteData.size(), + osl_getThreadTextEncoding()); + } + else + { + QByteArray aByteData(m_pMimeData->data(toQString(rFlavor.MimeType))); + aString = OUString(reinterpret_cast<const sal_Unicode*>(aByteData.data()), + aByteData.size() / 2); + } + aAny <<= aString; + } + else + { + QByteArray aByteData(m_pMimeData->data(toQString(rFlavor.MimeType))); + css::uno::Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(aByteData.data()), + aByteData.size()); + aAny <<= aSeq; + } + + return aAny; +} + +QtClipboardTransferable::QtClipboardTransferable(const QClipboard::Mode aMode, + const QMimeData* pMimeData) + : QtTransferable(pMimeData) + , m_aMode(aMode) +{ +} + +bool QtClipboardTransferable::hasInFlightChanged() const +{ + const bool bChanged(mimeData() != QApplication::clipboard()->mimeData(m_aMode)); + SAL_WARN_IF(bChanged, "vcl.qt5", + "In flight clipboard change detected - broken clipboard read!"); + return bChanged; +} + +css::uno::Any SAL_CALL +QtClipboardTransferable::getTransferData(const css::datatransfer::DataFlavor& rFlavor) +{ + css::uno::Any aAny; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([&, this]() { + if (!hasInFlightChanged()) + aAny = QtTransferable::getTransferData(rFlavor); + }); + return aAny; +} + +css::uno::Sequence<css::datatransfer::DataFlavor> + SAL_CALL QtClipboardTransferable::getTransferDataFlavors() +{ + css::uno::Sequence<css::datatransfer::DataFlavor> aSeq; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([&, this]() { + if (!hasInFlightChanged()) + aSeq = QtTransferable::getTransferDataFlavors(); + }); + return aSeq; +} + +sal_Bool SAL_CALL +QtClipboardTransferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) +{ + bool bIsSupported = false; + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([&, this]() { + if (!hasInFlightChanged()) + bIsSupported = QtTransferable::isDataFlavorSupported(rFlavor); + }); + return bIsSupported; +} + +QtMimeData::QtMimeData(const css::uno::Reference<css::datatransfer::XTransferable>& xTrans) + : m_aContents(xTrans) + , m_bHaveNoCharset(false) + , m_bHaveUTF8(false) +{ + assert(xTrans.is()); +} + +bool QtMimeData::deepCopy(QMimeData** const pMimeCopy) const +{ + if (!pMimeCopy) + return false; + + QMimeData* pMimeData = new QMimeData(); + for (QString& format : formats()) + { + QByteArray aData = data(format); + // Checking for custom MIME types + if (format.startsWith("application/x-qt")) + { + // Retrieving true format name + int indexBegin = format.indexOf('"') + 1; + int indexEnd = format.indexOf('"', indexBegin); + format = format.mid(indexBegin, indexEnd - indexBegin); + } + pMimeData->setData(format, aData); + } + + *pMimeCopy = pMimeData; + return true; +} + +QStringList QtMimeData::formats() const +{ + if (!m_aMimeTypeList.isEmpty()) + return m_aMimeTypeList; + + const css::uno::Sequence<css::datatransfer::DataFlavor> aFormats + = m_aContents->getTransferDataFlavors(); + QStringList aList; + bool bHaveUTF16 = false; + + for (const auto& rFlavor : aFormats) + { + aList << toQString(rFlavor.MimeType); + lcl_textMimeInfo(rFlavor.MimeType, m_bHaveNoCharset, bHaveUTF16, m_bHaveUTF8); + } + + // we provide a locale encoded and a UTF-8 variant, if missing + if (m_bHaveNoCharset || bHaveUTF16 || m_bHaveUTF8) + { + // if there is a text representation from LO point of view, it'll be UTF-16 + assert(bHaveUTF16); + if (!m_bHaveUTF8) + aList << QStringLiteral("text/plain;charset=utf-8"); + if (!m_bHaveNoCharset) + aList << QStringLiteral("text/plain"); + } + + m_aMimeTypeList = aList; + return m_aMimeTypeList; +} + +QVariant QtMimeData::retrieveData(const QString& mimeType, QVariant::Type) const +{ + if (!hasFormat(mimeType)) + return QVariant(); + + css::datatransfer::DataFlavor aFlavor; + aFlavor.MimeType = toOUString(mimeType); + aFlavor.DataType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(); + + bool bWantNoCharset = false, bWantUTF16 = false, bWantUTF8 = false; + if (lcl_textMimeInfo(aFlavor.MimeType, bWantNoCharset, bWantUTF16, bWantUTF8)) + { + if ((bWantNoCharset && !m_bHaveNoCharset) || (bWantUTF8 && !m_bHaveUTF8)) + { + aFlavor.MimeType = "text/plain;charset=utf-16"; + aFlavor.DataType = cppu::UnoType<OUString>::get(); + } + else if (bWantUTF16) + aFlavor.DataType = cppu::UnoType<OUString>::get(); + } + + css::uno::Any aValue; + + try + { + // tdf#129809 take a reference in case m_aContents is replaced during this call + css::uno::Reference<com::sun::star::datatransfer::XTransferable> xCurrentContents( + m_aContents); + aValue = xCurrentContents->getTransferData(aFlavor); + } + catch (...) + { + } + + QByteArray aByteArray; + if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING) + { + OUString aString; + aValue >>= aString; + + if (bWantUTF8) + { + OString aUTF8String(OUStringToOString(aString, RTL_TEXTENCODING_UTF8)); + aByteArray = QByteArray(reinterpret_cast<const char*>(aUTF8String.getStr()), + aUTF8String.getLength()); + } + else if (bWantNoCharset) + { + OString aLocaleString(OUStringToOString(aString, osl_getThreadTextEncoding())); + aByteArray = QByteArray(reinterpret_cast<const char*>(aLocaleString.getStr()), + aLocaleString.getLength()); + } + else + return QVariant(toQString(aString)); + } + else + { + css::uno::Sequence<sal_Int8> aData; + aValue >>= aData; + aByteArray + = QByteArray(reinterpret_cast<const char*>(aData.getConstArray()), aData.getLength()); + } + return QVariant::fromValue(aByteArray); +} + +bool QtMimeData::hasFormat(const QString& mimeType) const { return formats().contains(mimeType); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtVirtualDevice.cxx b/vcl/qt5/QtVirtualDevice.cxx new file mode 100644 index 000000000000..7e0dbab873d4 --- /dev/null +++ b/vcl/qt5/QtVirtualDevice.cxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtVirtualDevice.hxx> + +#include <QtGraphics.hxx> +#include <QtTools.hxx> + +#include <QtGui/QImage> + +QtVirtualDevice::QtVirtualDevice(double fScale) + : m_fScale(fScale) +{ +} + +SalGraphics* QtVirtualDevice::AcquireGraphics() +{ + assert(m_pImage); + QtGraphics* pGraphics = new QtGraphics(m_pImage.get()); + m_aGraphics.push_back(pGraphics); + return pGraphics; +} + +void QtVirtualDevice::ReleaseGraphics(SalGraphics* pGraphics) +{ + m_aGraphics.erase( + std::remove(m_aGraphics.begin(), m_aGraphics.end(), dynamic_cast<QtGraphics*>(pGraphics)), + m_aGraphics.end()); + delete pGraphics; +} + +bool QtVirtualDevice::SetSize(tools::Long nNewDX, tools::Long nNewDY) +{ + return SetSizeUsingBuffer(nNewDX, nNewDY, nullptr); +} + +bool QtVirtualDevice::SetSizeUsingBuffer(tools::Long nNewDX, tools::Long nNewDY, sal_uInt8* pBuffer) +{ + if (nNewDX == 0) + nNewDX = 1; + if (nNewDY == 0) + nNewDY = 1; + + if (m_pImage && m_aFrameSize.width() == nNewDX && m_aFrameSize.height() == nNewDY) + return true; + + m_aFrameSize = QSize(nNewDX, nNewDY); + + nNewDX *= m_fScale; + nNewDY *= m_fScale; + + if (pBuffer) + m_pImage.reset(new QImage(pBuffer, nNewDX, nNewDY, Qt_DefaultFormat32)); + else + m_pImage.reset(new QImage(nNewDX, nNewDY, Qt_DefaultFormat32)); + + m_pImage->fill(Qt::transparent); + m_pImage->setDevicePixelRatio(m_fScale); + + // update device in existing graphics + for (auto pQtGraph : m_aGraphics) + pQtGraph->ChangeQImage(m_pImage.get()); + + return true; +} + +tools::Long QtVirtualDevice::GetWidth() const { return m_pImage ? m_aFrameSize.width() : 0; } + +tools::Long QtVirtualDevice::GetHeight() const { return m_pImage ? m_aFrameSize.height() : 0; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtWidget.cxx b/vcl/qt5/QtWidget.cxx new file mode 100644 index 000000000000..12e101d48224 --- /dev/null +++ b/vcl/qt5/QtWidget.cxx @@ -0,0 +1,842 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <QtWidget.hxx> +#include <QtWidget.moc> + +#include <QtFrame.hxx> +#include <QtGraphics.hxx> +#include <QtInstance.hxx> +#include <QtSvpGraphics.hxx> +#include <QtTransferable.hxx> +#include <QtTools.hxx> + +#include <QtCore/QMimeData> +#include <QtGui/QDrag> +#include <QtGui/QFocusEvent> +#include <QtGui/QGuiApplication> +#include <QtGui/QImage> +#include <QtGui/QKeyEvent> +#include <QtGui/QMouseEvent> +#include <QtGui/QPainter> +#include <QtGui/QPaintEvent> +#include <QtGui/QResizeEvent> +#include <QtGui/QShowEvent> +#include <QtGui/QTextCharFormat> +#include <QtGui/QWheelEvent> +#include <QtWidgets/QMainWindow> +#include <QtWidgets/QWidget> + +#include <cairo.h> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/toolkit/floatwin.hxx> +#include <window.h> +#include <tools/diagnose_ex.h> + +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> + +#if QT5_USING_X11 +#define XK_MISCELLANY +#include <X11/keysymdef.h> +#endif + +using namespace com::sun::star; + +void QtWidget::paintEvent(QPaintEvent* pEvent) +{ + QPainter p(this); + if (!m_rFrame.m_bNullRegion) + p.setClipRegion(m_rFrame.m_aRegion); + + QImage aImage; + if (m_rFrame.m_bUseCairo) + { + cairo_surface_t* pSurface = m_rFrame.m_pSurface.get(); + cairo_surface_flush(pSurface); + + aImage = QImage(cairo_image_surface_get_data(pSurface), + cairo_image_surface_get_width(pSurface), + cairo_image_surface_get_height(pSurface), Qt_DefaultFormat32); + } + else + aImage = *m_rFrame.m_pQImage; + + const qreal fRatio = m_rFrame.devicePixelRatioF(); + aImage.setDevicePixelRatio(fRatio); + QRectF source(pEvent->rect().topLeft() * fRatio, pEvent->rect().size() * fRatio); + p.drawImage(pEvent->rect(), aImage, source); +} + +void QtWidget::resizeEvent(QResizeEvent* pEvent) +{ + const qreal fRatio = m_rFrame.devicePixelRatioF(); + const int nWidth = ceil(pEvent->size().width() * fRatio); + const int nHeight = ceil(pEvent->size().height() * fRatio); + + m_rFrame.maGeometry.nWidth = nWidth; + m_rFrame.maGeometry.nHeight = nHeight; + + if (m_rFrame.m_bUseCairo) + { + if (m_rFrame.m_pSvpGraphics) + { + cairo_surface_t* pSurface + = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight); + cairo_surface_set_user_data(pSurface, SvpSalGraphics::getDamageKey(), + &m_rFrame.m_aDamageHandler, nullptr); + m_rFrame.m_pSvpGraphics->setSurface(pSurface, basegfx::B2IVector(nWidth, nHeight)); + UniqueCairoSurface old_surface(m_rFrame.m_pSurface.release()); + m_rFrame.m_pSurface.reset(pSurface); + + int min_width = qMin(cairo_image_surface_get_width(old_surface.get()), nWidth); + int min_height = qMin(cairo_image_surface_get_height(old_surface.get()), nHeight); + + SalTwoRect rect(0, 0, min_width, min_height, 0, 0, min_width, min_height); + + m_rFrame.m_pSvpGraphics->copySource(rect, old_surface.get()); + } + } + else + { + QImage* pImage = nullptr; + + if (m_rFrame.m_pQImage) + pImage = new QImage(m_rFrame.m_pQImage->copy(0, 0, nWidth, nHeight)); + else + { + pImage = new QImage(nWidth, nHeight, Qt_DefaultFormat32); + pImage->fill(Qt::transparent); + } + + m_rFrame.m_pQtGraphics->ChangeQImage(pImage); + m_rFrame.m_pQImage.reset(pImage); + } + + m_rFrame.CallCallback(SalEvent::Resize, nullptr); +} + +void QtWidget::fillSalAbstractMouseEvent(const QtFrame& rFrame, const QInputEvent* pQEvent, + const QPoint& rPos, Qt::MouseButtons eButtons, int nWidth, + SalAbstractMouseEvent& aSalEvent) +{ + const qreal fRatio = rFrame.devicePixelRatioF(); + const Point aPos = toPoint(rPos * fRatio); + + aSalEvent.mnX = QGuiApplication::isLeftToRight() ? aPos.X() : round(nWidth * fRatio) - aPos.X(); + aSalEvent.mnY = aPos.Y(); + aSalEvent.mnTime = pQEvent->timestamp(); + aSalEvent.mnCode = GetKeyModCode(pQEvent->modifiers()) | GetMouseModCode(eButtons); +} + +#define FILL_SAME(rFrame, nWidth) \ + fillSalAbstractMouseEvent(rFrame, pEvent, pEvent->pos(), pEvent->buttons(), nWidth, aEvent) + +void QtWidget::handleMouseButtonEvent(const QtFrame& rFrame, const QMouseEvent* pEvent, + const ButtonKeyState eState) +{ + SalMouseEvent aEvent; + FILL_SAME(rFrame, rFrame.GetQWidget()->width()); + + switch (pEvent->button()) + { + case Qt::LeftButton: + aEvent.mnButton = MOUSE_LEFT; + break; + case Qt::MiddleButton: + aEvent.mnButton = MOUSE_MIDDLE; + break; + case Qt::RightButton: + aEvent.mnButton = MOUSE_RIGHT; + break; + default: + return; + } + + SalEvent nEventType; + if (eState == ButtonKeyState::Pressed) + nEventType = SalEvent::MouseButtonDown; + else + nEventType = SalEvent::MouseButtonUp; + rFrame.CallCallback(nEventType, &aEvent); +} + +void QtWidget::mousePressEvent(QMouseEvent* pEvent) +{ + handleMousePressEvent(m_rFrame, pEvent); + if (m_rFrame.isPopup() + && !geometry().translated(geometry().topLeft() * -1).contains(pEvent->pos())) + closePopup(); +} + +void QtWidget::mouseReleaseEvent(QMouseEvent* pEvent) { handleMouseReleaseEvent(m_rFrame, pEvent); } + +void QtWidget::mouseMoveEvent(QMouseEvent* pEvent) +{ + SalMouseEvent aEvent; + FILL_SAME(m_rFrame, width()); + + aEvent.mnButton = 0; + + m_rFrame.CallCallback(SalEvent::MouseMove, &aEvent); + pEvent->accept(); +} + +void QtWidget::wheelEvent(QWheelEvent* pEvent) +{ + SalWheelMouseEvent aEvent; +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + fillSalAbstractMouseEvent(m_rFrame, pEvent, pEvent->position().toPoint(), pEvent->buttons(), + width(), aEvent); +#else + fillSalAbstractMouseEvent(m_rFrame, pEvent, pEvent->pos(), pEvent->buttons(), width(), aEvent); +#endif + + // mouse wheel ticks are 120, which we map to 3 lines. + // we have to accumulate for touch scroll to keep track of the absolute delta. + + int nDelta = pEvent->angleDelta().y(), lines; + aEvent.mbHorz = nDelta == 0; + if (aEvent.mbHorz) + { + nDelta = (QGuiApplication::isLeftToRight() ? 1 : -1) * pEvent->angleDelta().x(); + if (!nDelta) + return; + + m_nDeltaX += nDelta; + lines = m_nDeltaX / 40; + m_nDeltaX = m_nDeltaX % 40; + } + else + { + m_nDeltaY += nDelta; + lines = m_nDeltaY / 40; + m_nDeltaY = m_nDeltaY % 40; + } + + aEvent.mnDelta = nDelta; + aEvent.mnNotchDelta = nDelta < 0 ? -1 : 1; + aEvent.mnScrollLines = std::abs(lines); + + m_rFrame.CallCallback(SalEvent::WheelMouse, &aEvent); + pEvent->accept(); +} + +void QtWidget::dragEnterEvent(QDragEnterEvent* event) +{ + if (dynamic_cast<const QtMimeData*>(event->mimeData())) + event->accept(); + else + event->acceptProposedAction(); +} + +// also called when a drop is rejected +void QtWidget::dragLeaveEvent(QDragLeaveEvent*) { m_rFrame.handleDragLeave(); } + +void QtWidget::dragMoveEvent(QDragMoveEvent* pEvent) { m_rFrame.handleDragMove(pEvent); } + +void QtWidget::dropEvent(QDropEvent* pEvent) { m_rFrame.handleDrop(pEvent); } + +void QtWidget::moveEvent(QMoveEvent* pEvent) +{ + if (m_rFrame.m_pTopLevel) + return; + + const Point aPos = toPoint(pEvent->pos() * m_rFrame.devicePixelRatioF()); + m_rFrame.maGeometry.nX = aPos.X(); + m_rFrame.maGeometry.nY = aPos.Y(); + m_rFrame.CallCallback(SalEvent::Move, nullptr); +} + +void QtWidget::showEvent(QShowEvent*) +{ + QSize aSize(m_rFrame.GetQWidget()->size() * m_rFrame.devicePixelRatioF()); + // forcing an immediate update somehow interferes with the hide + show + // sequence from QtFrame::SetModal, if the frame was already set visible, + // resulting in a hidden / unmapped window + SalPaintEvent aPaintEvt(0, 0, aSize.width(), aSize.height()); + m_rFrame.CallCallback(SalEvent::Paint, &aPaintEvt); +} + +void QtWidget::closeEvent(QCloseEvent* /*pEvent*/) +{ + m_rFrame.CallCallback(SalEvent::Close, nullptr); +} + +static sal_uInt16 GetKeyCode(int keyval, Qt::KeyboardModifiers modifiers) +{ + sal_uInt16 nCode = 0; + if (keyval >= Qt::Key_0 && keyval <= Qt::Key_9) + nCode = KEY_0 + (keyval - Qt::Key_0); + else if (keyval >= Qt::Key_A && keyval <= Qt::Key_Z) + nCode = KEY_A + (keyval - Qt::Key_A); + else if (keyval >= Qt::Key_F1 && keyval <= Qt::Key_F26) + nCode = KEY_F1 + (keyval - Qt::Key_F1); + else if (modifiers.testFlag(Qt::KeypadModifier) + && (keyval == Qt::Key_Period || keyval == Qt::Key_Comma)) + // Qt doesn't use a special keyval for decimal separator ("," or ".") + // on numerical keypad, but sets Qt::KeypadModifier in addition + nCode = KEY_DECIMAL; + else + { + switch (keyval) + { + case Qt::Key_Down: + nCode = KEY_DOWN; + break; + case Qt::Key_Up: + nCode = KEY_UP; + break; + case Qt::Key_Left: + nCode = KEY_LEFT; + break; + case Qt::Key_Right: + nCode = KEY_RIGHT; + break; + case Qt::Key_Home: + nCode = KEY_HOME; + break; + case Qt::Key_End: + nCode = KEY_END; + break; + case Qt::Key_PageUp: + nCode = KEY_PAGEUP; + break; + case Qt::Key_PageDown: + nCode = KEY_PAGEDOWN; + break; + case Qt::Key_Return: + case Qt::Key_Enter: + nCode = KEY_RETURN; + break; + case Qt::Key_Escape: + nCode = KEY_ESCAPE; + break; + case Qt::Key_Tab: + // oddly enough, Qt doesn't send Shift-Tab event as 'Tab key pressed with Shift + // modifier' but as 'Backtab key pressed' (while its modifier bits are still + // set to Shift) -- so let's map both Key_Tab and Key_Backtab to VCL's KEY_TAB + case Qt::Key_Backtab: + nCode = KEY_TAB; + break; + case Qt::Key_Backspace: + nCode = KEY_BACKSPACE; + break; + case Qt::Key_Space: + nCode = KEY_SPACE; + break; + case Qt::Key_Insert: + nCode = KEY_INSERT; + break; + case Qt::Key_Delete: + nCode = KEY_DELETE; + break; + case Qt::Key_Plus: + nCode = KEY_ADD; + break; + case Qt::Key_Minus: + nCode = KEY_SUBTRACT; + break; + case Qt::Key_Asterisk: + nCode = KEY_MULTIPLY; + break; + case Qt::Key_Slash: + nCode = KEY_DIVIDE; + break; + case Qt::Key_Period: + nCode = KEY_POINT; + break; + case Qt::Key_Comma: + nCode = KEY_COMMA; + break; + case Qt::Key_Less: + nCode = KEY_LESS; + break; + case Qt::Key_Greater: + nCode = KEY_GREATER; + break; + case Qt::Key_Equal: + nCode = KEY_EQUAL; + break; + case Qt::Key_Find: + nCode = KEY_FIND; + break; + case Qt::Key_Menu: + nCode = KEY_CONTEXTMENU; + break; + case Qt::Key_Help: + nCode = KEY_HELP; + break; + case Qt::Key_Undo: + nCode = KEY_UNDO; + break; + case Qt::Key_Redo: + nCode = KEY_REPEAT; + break; + case Qt::Key_Cancel: + nCode = KEY_F11; + break; + case Qt::Key_AsciiTilde: + nCode = KEY_TILDE; + break; + case Qt::Key_QuoteLeft: + nCode = KEY_QUOTELEFT; + break; + case Qt::Key_BracketLeft: + nCode = KEY_BRACKETLEFT; + break; + case Qt::Key_BracketRight: + nCode = KEY_BRACKETRIGHT; + break; + case Qt::Key_Semicolon: + nCode = KEY_SEMICOLON; + break; + case Qt::Key_Copy: + nCode = KEY_COPY; + break; + case Qt::Key_Cut: + nCode = KEY_CUT; + break; + case Qt::Key_Open: + nCode = KEY_OPEN; + break; + case Qt::Key_Paste: + nCode = KEY_PASTE; + break; + } + } + + return nCode; +} + +void QtWidget::commitText(QtFrame& rFrame, const QString& aText) +{ + SalExtTextInputEvent aInputEvent; + aInputEvent.mpTextAttr = nullptr; + aInputEvent.mnCursorFlags = 0; + aInputEvent.maText = toOUString(aText); + aInputEvent.mnCursorPos = aInputEvent.maText.getLength(); + + SolarMutexGuard aGuard; + vcl::DeletionListener aDel(&rFrame); + rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent); + if (!aDel.isDeleted()) + rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); +} + +bool QtWidget::handleKeyEvent(QtFrame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent, + const ButtonKeyState eState) +{ + sal_uInt16 nCode = GetKeyCode(pEvent->key(), pEvent->modifiers()); + if (eState == ButtonKeyState::Pressed && nCode == 0 && pEvent->text().length() > 1 + && rWidget.testAttribute(Qt::WA_InputMethodEnabled)) + { + commitText(rFrame, pEvent->text()); + pEvent->accept(); + return true; + } + + if (nCode == 0 && pEvent->text().isEmpty()) + { + sal_uInt16 nModCode = GetKeyModCode(pEvent->modifiers()); + SalKeyModEvent aModEvt; + aModEvt.mbDown = eState == ButtonKeyState::Pressed; + aModEvt.mnModKeyCode = ModKeyFlags::NONE; + +#if QT5_USING_X11 + if (QGuiApplication::platformName() == "xcb") + { + // pressing just the ctrl key leads to a keysym of XK_Control but + // the event state does not contain ControlMask. In the release + // event it's the other way round: it does contain the Control mask. + // The modifier mode therefore has to be adapted manually. + ModKeyFlags nExtModMask = ModKeyFlags::NONE; + sal_uInt16 nModMask = 0; + switch (pEvent->nativeVirtualKey()) + { + case XK_Control_L: + nExtModMask = ModKeyFlags::LeftMod1; + nModMask = KEY_MOD1; + break; + case XK_Control_R: + nExtModMask = ModKeyFlags::RightMod1; + nModMask = KEY_MOD1; + break; + case XK_Alt_L: + nExtModMask = ModKeyFlags::LeftMod2; + nModMask = KEY_MOD2; + break; + case XK_Alt_R: + nExtModMask = ModKeyFlags::RightMod2; + nModMask = KEY_MOD2; + break; + case XK_Shift_L: + nExtModMask = ModKeyFlags::LeftShift; + nModMask = KEY_SHIFT; + break; + case XK_Shift_R: + nExtModMask = ModKeyFlags::RightShift; + nModMask = KEY_SHIFT; + break; + // Map Meta/Super keys to MOD3 modifier on all Unix systems + // except macOS + case XK_Meta_L: + case XK_Super_L: + nExtModMask = ModKeyFlags::LeftMod3; + nModMask = KEY_MOD3; + break; + case XK_Meta_R: + case XK_Super_R: + nExtModMask = ModKeyFlags::RightMod3; + nModMask = KEY_MOD3; + break; + } + + if (eState == ButtonKeyState::Released) + { + // sending the old mnModKeyCode mask on release is needed to + // implement the writing direction switch with Ctrl + L/R-Shift + aModEvt.mnModKeyCode = rFrame.m_nKeyModifiers; + nModCode &= ~nModMask; + rFrame.m_nKeyModifiers &= ~nExtModMask; + } + else + { + nModCode |= nModMask; + rFrame.m_nKeyModifiers |= nExtModMask; + aModEvt.mnModKeyCode = rFrame.m_nKeyModifiers; + } + } +#endif + aModEvt.mnCode = nModCode; + + rFrame.CallCallback(SalEvent::KeyModChange, &aModEvt); + return false; + } + + // prevent interference of writing direction switch (Ctrl + L/R-Shift) with "normal" shortcuts + rFrame.m_nKeyModifiers = ModKeyFlags::NONE; + + SalKeyEvent aEvent; + aEvent.mnCharCode = (pEvent->text().isEmpty() ? 0 : pEvent->text().at(0).unicode()); + aEvent.mnRepeat = 0; + aEvent.mnCode = nCode; + aEvent.mnCode |= GetKeyModCode(pEvent->modifiers()); + + QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle); + + bool bStopProcessingKey; + if (eState == ButtonKeyState::Pressed) + bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyInput, &aEvent); + else + bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyUp, &aEvent); + if (bStopProcessingKey) + pEvent->accept(); + return bStopProcessingKey; +} + +bool QtWidget::handleEvent(QtFrame& rFrame, const QWidget& rWidget, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::ShortcutOverride) + { + // ignore non-spontaneous QEvent::ShortcutOverride events, + // since such an extra event is sent e.g. with Orca screen reader enabled, + // so that two events of that kind (the "real one" and a non-spontaneous one) + // would otherwise be processed, resulting in duplicate input as 'handleKeyEvent' + // is called below (s. tdf#122053) + if (!pEvent->spontaneous()) + { + return false; + } + + // Accepted event disables shortcut activation, + // but enables keypress event. + // If event is not accepted and shortcut is successfully activated, + // KeyPress event is omitted. + // + // Instead of processing keyPressEvent, handle ShortcutOverride event, + // and if it's handled - disable the shortcut, it should have been activated. + // Don't process keyPressEvent generated after disabling shortcut since it was handled here. + // If event is not handled, don't accept it and let Qt activate related shortcut. + if (handleKeyEvent(rFrame, rWidget, static_cast<QKeyEvent*>(pEvent), + ButtonKeyState::Pressed)) + return true; + } + return false; +} + +bool QtWidget::event(QEvent* pEvent) +{ + return handleEvent(m_rFrame, *this, pEvent) || QWidget::event(pEvent); +} + +void QtWidget::keyReleaseEvent(QKeyEvent* pEvent) +{ + if (!handleKeyReleaseEvent(m_rFrame, *this, pEvent)) + QWidget::keyReleaseEvent(pEvent); +} + +void QtWidget::focusInEvent(QFocusEvent*) { m_rFrame.CallCallback(SalEvent::GetFocus, nullptr); } + +void QtWidget::closePopup() +{ + VclPtr<FloatingWindow> pFirstFloat = ImplGetSVData()->mpWinData->mpFirstFloat; + if (pFirstFloat && !(pFirstFloat->GetPopupModeFlags() & FloatWinPopupFlags::NoAppFocusClose)) + { + SolarMutexGuard aGuard; + pFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll); + } +} + +void QtWidget::focusOutEvent(QFocusEvent*) +{ + m_rFrame.m_nKeyModifiers = ModKeyFlags::NONE; + endExtTextInput(); + m_rFrame.CallCallback(SalEvent::LoseFocus, nullptr); + closePopup(); +} + +QtWidget::QtWidget(QtFrame& rFrame, Qt::WindowFlags f) + : QWidget(Q_NULLPTR, f) + , m_rFrame(rFrame) + , m_bNonEmptyIMPreeditSeen(false) + , m_nDeltaX(0) + , m_nDeltaY(0) +{ + create(); + setMouseTracking(true); + setFocusPolicy(Qt::StrongFocus); +} + +static ExtTextInputAttr lcl_MapUndrelineStyle(QTextCharFormat::UnderlineStyle us) +{ + switch (us) + { + case QTextCharFormat::NoUnderline: + return ExtTextInputAttr::NONE; + case QTextCharFormat::DotLine: + return ExtTextInputAttr::DottedUnderline; + case QTextCharFormat::DashDotDotLine: + case QTextCharFormat::DashDotLine: + return ExtTextInputAttr::DashDotUnderline; + case QTextCharFormat::WaveUnderline: + return ExtTextInputAttr::GrayWaveline; + default: + return ExtTextInputAttr::Underline; + } +} + +void QtWidget::inputMethodEvent(QInputMethodEvent* pEvent) +{ + if (!pEvent->commitString().isEmpty()) + commitText(m_rFrame, pEvent->commitString()); + else + { + SalExtTextInputEvent aInputEvent; + aInputEvent.mpTextAttr = nullptr; + aInputEvent.mnCursorFlags = 0; + aInputEvent.maText = toOUString(pEvent->preeditString()); + aInputEvent.mnCursorPos = 0; + + const sal_Int32 nLength = aInputEvent.maText.getLength(); + const QList<QInputMethodEvent::Attribute>& rAttrList = pEvent->attributes(); + std::vector<ExtTextInputAttr> aTextAttrs(std::max(sal_Int32(1), nLength), + ExtTextInputAttr::NONE); + aInputEvent.mpTextAttr = aTextAttrs.data(); + + for (int i = 0; i < rAttrList.size(); ++i) + { + const QInputMethodEvent::Attribute& rAttr = rAttrList.at(i); + switch (rAttr.type) + { + case QInputMethodEvent::TextFormat: + { + QTextCharFormat aCharFormat + = qvariant_cast<QTextFormat>(rAttr.value).toCharFormat(); + if (aCharFormat.isValid()) + { + ExtTextInputAttr aETIP + = lcl_MapUndrelineStyle(aCharFormat.underlineStyle()); + if (aCharFormat.hasProperty(QTextFormat::BackgroundBrush)) + aETIP |= ExtTextInputAttr::Highlight; + if (aCharFormat.fontStrikeOut()) + aETIP |= ExtTextInputAttr::RedText; + for (int j = rAttr.start; j < rAttr.start + rAttr.length; j++) + aTextAttrs[j] = aETIP; + } + break; + } + case QInputMethodEvent::Cursor: + { + aInputEvent.mnCursorPos = rAttr.start; + if (rAttr.length == 0) + aInputEvent.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE; + break; + } + default: + SAL_WARN("vcl.qt5", "Unhandled QInputMethodEvent attribute: " + << static_cast<int>(rAttr.type)); + break; + } + } + + const bool bIsEmpty = aInputEvent.maText.isEmpty(); + if (m_bNonEmptyIMPreeditSeen || !bIsEmpty) + { + SolarMutexGuard aGuard; + vcl::DeletionListener aDel(&m_rFrame); + m_rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent); + if (!aDel.isDeleted() && bIsEmpty) + m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); + m_bNonEmptyIMPreeditSeen = !bIsEmpty; + } + } + + pEvent->accept(); +} + +static bool lcl_retrieveSurrounding(sal_Int32& rPosition, sal_Int32& rAnchor, QString* pText, + QString* pSelection) +{ + SolarMutexGuard aGuard; + vcl::Window* pFocusWin = Application::GetFocusWindow(); + if (!pFocusWin) + return false; + + uno::Reference<accessibility::XAccessibleEditableText> xText; + try + { + uno::Reference<accessibility::XAccessible> xAccessible(pFocusWin->GetAccessible()); + if (xAccessible.is()) + xText = FindFocusedEditableText(xAccessible->getAccessibleContext()); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("vcl.qt5", "Exception in getting input method surrounding text"); + } + + if (xText.is()) + { + rPosition = xText->getCaretPosition(); + if (rPosition != -1) + { + if (pText) + *pText = toQString(xText->getText()); + + sal_Int32 nSelStart = xText->getSelectionStart(); + sal_Int32 nSelEnd = xText->getSelectionEnd(); + if (nSelStart == nSelEnd) + { + rAnchor = rPosition; + } + else + { + if (rPosition == nSelStart) + rAnchor = nSelEnd; + else + rAnchor = nSelStart; + if (pSelection) + *pSelection = toQString(xText->getSelectedText()); + } + return true; + } + } + + return false; +} + +QVariant QtWidget::inputMethodQuery(Qt::InputMethodQuery property) const +{ + switch (property) + { + case Qt::ImSurroundingText: + { + QString aText; + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, &aText, nullptr)) + return QVariant(aText); + return QVariant(); + } + case Qt::ImCursorPosition: + { + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr)) + return QVariant(static_cast<int>(nCursorPos)); + return QVariant(); + } + case Qt::ImCursorRectangle: + { + const qreal fRatio = m_rFrame.devicePixelRatioF(); + SalExtTextInputPosEvent aPosEvent; + m_rFrame.CallCallback(SalEvent::ExtTextInputPos, &aPosEvent); + return QVariant(QRect(aPosEvent.mnX / fRatio, aPosEvent.mnY / fRatio, + aPosEvent.mnWidth / fRatio, aPosEvent.mnHeight / fRatio)); + } + case Qt::ImAnchorPosition: + { + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr)) + return QVariant(static_cast<int>(nAnchor)); + return QVariant(); + } + case Qt::ImCurrentSelection: + { + QString aSelection; + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, &aSelection)) + return QVariant(aSelection); + return QVariant(); + } + default: + return QWidget::inputMethodQuery(property); + } +} + +void QtWidget::endExtTextInput() +{ + if (m_bNonEmptyIMPreeditSeen) + { + m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); + m_bNonEmptyIMPreeditSeen = false; + } +} + +void QtWidget::changeEvent(QEvent* pEvent) +{ + switch (pEvent->type()) + { + case QEvent::FontChange: + [[fallthrough]]; + case QEvent::PaletteChange: + [[fallthrough]]; + case QEvent::StyleChange: + { + auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->UpdateStyle(QEvent::FontChange == pEvent->type()); + break; + } + default: + break; + } + QWidget::changeEvent(pEvent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtXAccessible.cxx b/vcl/qt5/QtXAccessible.cxx new file mode 100644 index 000000000000..c8ef055a2429 --- /dev/null +++ b/vcl/qt5/QtXAccessible.cxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <QtXAccessible.hxx> +#include <QtXAccessible.moc> + +#include <QtFrame.hxx> +#include <QtTools.hxx> +#include <QtWidget.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> + +#include <sal/log.hxx> + +using namespace css::accessibility; +using namespace css::uno; + +QtXAccessible::QtXAccessible(Reference<XAccessible> xAccessible) + : m_xAccessible(xAccessible) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kf5/KF5FilePicker.cxx b/vcl/unx/kf5/KF5FilePicker.cxx index b9f665925e47..2cef6954c2ce 100644 --- a/vcl/unx/kf5/KF5FilePicker.cxx +++ b/vcl/unx/kf5/KF5FilePicker.cxx @@ -24,7 +24,7 @@ #include <cppuhelper/supportsservice.hxx> #include <osl/mutex.hxx> -#include <Qt5Instance.hxx> +#include <QtInstance.hxx> #include <QtWidgets/QApplication> #include <QtWidgets/QGridLayout> diff --git a/vcl/unx/kf5/KF5FilePicker.hxx b/vcl/unx/kf5/KF5FilePicker.hxx index 81a0ca2a1e4b..29989eb1bbd4 100644 --- a/vcl/unx/kf5/KF5FilePicker.hxx +++ b/vcl/unx/kf5/KF5FilePicker.hxx @@ -19,7 +19,7 @@ #pragma once -#include <Qt5FilePicker.hxx> +#include <QtFilePicker.hxx> #include <memory> class QGridLayout; diff --git a/vcl/unx/kf5/KF5SalFrame.cxx b/vcl/unx/kf5/KF5SalFrame.cxx index 198f8ccf28f8..f33011837470 100644 --- a/vcl/unx/kf5/KF5SalFrame.cxx +++ b/vcl/unx/kf5/KF5SalFrame.cxx @@ -28,7 +28,7 @@ #include <KConfigGroup> #include <KSharedConfig> -#include <Qt5FontFace.hxx> +#include <QtFontFace.hxx> #include "KF5SalFrame.hxx" #include <tools/color.hxx> diff --git a/vcl/unx/kf5/KF5SalFrame.hxx b/vcl/unx/kf5/KF5SalFrame.hxx index 8633f5d37141..d7c82c375a9d 100644 --- a/vcl/unx/kf5/KF5SalFrame.hxx +++ b/vcl/unx/kf5/KF5SalFrame.hxx @@ -21,8 +21,8 @@ #include <memory> -#include <Qt5Frame.hxx> -#include <Qt5SvpGraphics.hxx> +#include <QtFrame.hxx> +#include <QtSvpGraphics.hxx> class QWidget; diff --git a/vcl/unx/kf5/KF5SalInstance.cxx b/vcl/unx/kf5/KF5SalInstance.cxx index 6cd974d59908..efcfd0963451 100644 --- a/vcl/unx/kf5/KF5SalInstance.cxx +++ b/vcl/unx/kf5/KF5SalInstance.cxx @@ -25,7 +25,7 @@ #include <sal/log.hxx> -#include <Qt5Data.hxx> +#include <QtData.hxx> #include "KF5FilePicker.hxx" #include "KF5SalFrame.hxx" diff --git a/vcl/unx/kf5/KF5SalInstance.hxx b/vcl/unx/kf5/KF5SalInstance.hxx index a50efb75b9c5..add3b112af98 100644 --- a/vcl/unx/kf5/KF5SalInstance.hxx +++ b/vcl/unx/kf5/KF5SalInstance.hxx @@ -19,7 +19,7 @@ #pragma once -#include <Qt5Instance.hxx> +#include <QtInstance.hxx> class KF5SalInstance final : public QtInstance { -- cgit