Update git submodules
[LibreOffice.git] / vcl / qt5 / Qt5Widget.cxx
bloba2bf8fe6472da75c426f3da7e4e47efcd07610e3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <Qt5Widget.hxx>
21 #include <Qt5Widget.moc>
23 #include <Qt5Frame.hxx>
24 #include <Qt5Graphics.hxx>
25 #include <Qt5Instance.hxx>
26 #include <Qt5SvpGraphics.hxx>
27 #include <Qt5Transferable.hxx>
28 #include <Qt5Tools.hxx>
30 #include <QtCore/QMimeData>
31 #include <QtGui/QDrag>
32 #include <QtGui/QFocusEvent>
33 #include <QtGui/QGuiApplication>
34 #include <QtGui/QImage>
35 #include <QtGui/QKeyEvent>
36 #include <QtGui/QMouseEvent>
37 #include <QtGui/QPainter>
38 #include <QtGui/QPaintEvent>
39 #include <QtGui/QResizeEvent>
40 #include <QtGui/QShowEvent>
41 #include <QtGui/QTextCharFormat>
42 #include <QtGui/QWheelEvent>
43 #include <QtWidgets/QMainWindow>
44 #include <QtWidgets/QWidget>
46 #include <cairo.h>
47 #include <vcl/commandevent.hxx>
48 #include <vcl/event.hxx>
49 #include <window.h>
50 #include <tools/diagnose_ex.h>
52 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
53 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
55 using namespace com::sun::star;
57 void Qt5Widget::paintEvent(QPaintEvent* pEvent)
59 QPainter p(this);
60 if (!m_rFrame.m_bNullRegion)
61 p.setClipRegion(m_rFrame.m_aRegion);
63 QImage aImage;
64 if (m_rFrame.m_bUseCairo)
66 cairo_surface_t* pSurface = m_rFrame.m_pSurface.get();
67 cairo_surface_flush(pSurface);
69 aImage = QImage(cairo_image_surface_get_data(pSurface),
70 cairo_image_surface_get_width(pSurface),
71 cairo_image_surface_get_height(pSurface), Qt5_DefaultFormat32);
73 else
74 aImage = *m_rFrame.m_pQImage;
76 const qreal fRatio = m_rFrame.devicePixelRatioF();
77 aImage.setDevicePixelRatio(fRatio);
78 QRectF source(pEvent->rect().topLeft() * fRatio, pEvent->rect().size() * fRatio);
79 p.drawImage(pEvent->rect(), aImage, source);
82 void Qt5Widget::resizeEvent(QResizeEvent* pEvent)
84 const qreal fRatio = m_rFrame.devicePixelRatioF();
85 const int nWidth = ceil(pEvent->size().width() * fRatio);
86 const int nHeight = ceil(pEvent->size().height() * fRatio);
88 m_rFrame.maGeometry.nWidth = nWidth;
89 m_rFrame.maGeometry.nHeight = nHeight;
91 if (m_rFrame.m_bUseCairo)
93 if (m_rFrame.m_pSvpGraphics)
95 cairo_surface_t* pSurface
96 = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight);
97 cairo_surface_set_user_data(pSurface, SvpSalGraphics::getDamageKey(),
98 &m_rFrame.m_aDamageHandler, nullptr);
99 m_rFrame.m_pSvpGraphics->setSurface(pSurface, basegfx::B2IVector(nWidth, nHeight));
100 UniqueCairoSurface old_surface(m_rFrame.m_pSurface.release());
101 m_rFrame.m_pSurface.reset(pSurface);
103 int min_width = qMin(cairo_image_surface_get_width(old_surface.get()), nWidth);
104 int min_height = qMin(cairo_image_surface_get_height(old_surface.get()), nHeight);
106 SalTwoRect rect(0, 0, min_width, min_height, 0, 0, min_width, min_height);
108 m_rFrame.m_pSvpGraphics->copySource(rect, old_surface.get());
111 else
113 QImage* pImage = nullptr;
115 if (m_rFrame.m_pQImage)
116 pImage = new QImage(m_rFrame.m_pQImage->copy(0, 0, nWidth, nHeight));
117 else
119 pImage = new QImage(nWidth, nHeight, Qt5_DefaultFormat32);
120 pImage->fill(Qt::transparent);
123 m_rFrame.m_pQt5Graphics->ChangeQImage(pImage);
124 m_rFrame.m_pQImage.reset(pImage);
127 m_rFrame.CallCallback(SalEvent::Resize, nullptr);
130 void Qt5Widget::fillSalAbstractMouseEvent(const Qt5Frame& rFrame, const QInputEvent* pQEvent,
131 const QPoint& rPos, Qt::MouseButtons eButtons, int nWidth,
132 SalAbstractMouseEvent& aSalEvent)
134 const qreal fRatio = rFrame.devicePixelRatioF();
135 const Point aPos = toPoint(rPos * fRatio);
137 aSalEvent.mnX = QGuiApplication::isLeftToRight() ? aPos.X() : round(nWidth * fRatio) - aPos.X();
138 aSalEvent.mnY = aPos.Y();
139 aSalEvent.mnTime = pQEvent->timestamp();
140 aSalEvent.mnCode = GetKeyModCode(pQEvent->modifiers()) | GetMouseModCode(eButtons);
143 #define FILL_SAME(rFrame, nWidth) \
144 fillSalAbstractMouseEvent(rFrame, pEvent, pEvent->pos(), pEvent->buttons(), nWidth, aEvent)
146 void Qt5Widget::handleMouseButtonEvent(const Qt5Frame& rFrame, const QMouseEvent* pEvent,
147 const ButtonKeyState eState)
149 SalMouseEvent aEvent;
150 FILL_SAME(rFrame, rFrame.GetQWidget()->width());
152 switch (pEvent->button())
154 case Qt::LeftButton:
155 aEvent.mnButton = MOUSE_LEFT;
156 break;
157 case Qt::MiddleButton:
158 aEvent.mnButton = MOUSE_MIDDLE;
159 break;
160 case Qt::RightButton:
161 aEvent.mnButton = MOUSE_RIGHT;
162 break;
163 default:
164 return;
167 SalEvent nEventType;
168 if (eState == ButtonKeyState::Pressed)
169 nEventType = SalEvent::MouseButtonDown;
170 else
171 nEventType = SalEvent::MouseButtonUp;
172 rFrame.CallCallback(nEventType, &aEvent);
175 void Qt5Widget::mousePressEvent(QMouseEvent* pEvent) { handleMousePressEvent(m_rFrame, pEvent); }
177 void Qt5Widget::mouseReleaseEvent(QMouseEvent* pEvent)
179 handleMouseReleaseEvent(m_rFrame, pEvent);
182 void Qt5Widget::mouseMoveEvent(QMouseEvent* pEvent)
184 SalMouseEvent aEvent;
185 FILL_SAME(m_rFrame, width());
187 aEvent.mnButton = 0;
189 m_rFrame.CallCallback(SalEvent::MouseMove, &aEvent);
190 pEvent->accept();
193 void Qt5Widget::wheelEvent(QWheelEvent* pEvent)
195 SalWheelMouseEvent aEvent;
196 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
197 fillSalAbstractMouseEvent(m_rFrame, pEvent, pEvent->position().toPoint(), pEvent->buttons(),
198 width(), aEvent);
199 #else
200 fillSalAbstractMouseEvent(m_rFrame, pEvent, pEvent->pos(), pEvent->buttons(), width(), aEvent);
201 #endif
203 // mouse wheel ticks are 120, which we map to 3 lines.
204 // we have to accumulate for touch scroll to keep track of the absolute delta.
206 int nDelta = pEvent->angleDelta().y(), lines;
207 aEvent.mbHorz = nDelta == 0;
208 if (aEvent.mbHorz)
210 nDelta = (QGuiApplication::isLeftToRight() ? 1 : -1) * pEvent->angleDelta().x();
211 if (!nDelta)
212 return;
214 m_nDeltaX += nDelta;
215 lines = m_nDeltaX / 40;
216 m_nDeltaX = m_nDeltaX % 40;
218 else
220 m_nDeltaY += nDelta;
221 lines = m_nDeltaY / 40;
222 m_nDeltaY = m_nDeltaY % 40;
225 aEvent.mnDelta = nDelta;
226 aEvent.mnNotchDelta = nDelta < 0 ? -1 : 1;
227 aEvent.mnScrollLines = std::abs(lines);
229 m_rFrame.CallCallback(SalEvent::WheelMouse, &aEvent);
230 pEvent->accept();
233 void Qt5Widget::dragEnterEvent(QDragEnterEvent* event)
235 if (dynamic_cast<const Qt5MimeData*>(event->mimeData()))
236 event->accept();
237 else
238 event->acceptProposedAction();
241 // also called when a drop is rejected
242 void Qt5Widget::dragLeaveEvent(QDragLeaveEvent*) { m_rFrame.handleDragLeave(); }
244 void Qt5Widget::dragMoveEvent(QDragMoveEvent* pEvent) { m_rFrame.handleDragMove(pEvent); }
246 void Qt5Widget::dropEvent(QDropEvent* pEvent) { m_rFrame.handleDrop(pEvent); }
248 void Qt5Widget::moveEvent(QMoveEvent* pEvent)
250 if (m_rFrame.m_pTopLevel)
251 return;
253 const Point aPos = toPoint(pEvent->pos() * m_rFrame.devicePixelRatioF());
254 m_rFrame.maGeometry.nX = aPos.X();
255 m_rFrame.maGeometry.nY = aPos.Y();
256 m_rFrame.CallCallback(SalEvent::Move, nullptr);
259 void Qt5Widget::showEvent(QShowEvent*)
261 QSize aSize(m_rFrame.GetQWidget()->size() * m_rFrame.devicePixelRatioF());
262 // forcing an immediate update somehow interferes with the hide + show
263 // sequence from Qt5Frame::SetModal, if the frame was already set visible,
264 // resulting in a hidden / unmapped window
265 SalPaintEvent aPaintEvt(0, 0, aSize.width(), aSize.height());
266 m_rFrame.CallCallback(SalEvent::Paint, &aPaintEvt);
269 void Qt5Widget::closeEvent(QCloseEvent* /*pEvent*/)
271 m_rFrame.CallCallback(SalEvent::Close, nullptr);
274 static sal_uInt16 GetKeyCode(int keyval, Qt::KeyboardModifiers modifiers)
276 sal_uInt16 nCode = 0;
277 if (keyval >= Qt::Key_0 && keyval <= Qt::Key_9)
278 nCode = KEY_0 + (keyval - Qt::Key_0);
279 else if (keyval >= Qt::Key_A && keyval <= Qt::Key_Z)
280 nCode = KEY_A + (keyval - Qt::Key_A);
281 else if (keyval >= Qt::Key_F1 && keyval <= Qt::Key_F26)
282 nCode = KEY_F1 + (keyval - Qt::Key_F1);
283 else if (modifiers.testFlag(Qt::KeypadModifier)
284 && (keyval == Qt::Key_Period || keyval == Qt::Key_Comma))
285 // Qt doesn't use a special keyval for decimal separator ("," or ".")
286 // on numerical keypad, but sets Qt::KeypadModifier in addition
287 nCode = KEY_DECIMAL;
288 else
290 switch (keyval)
292 case Qt::Key_Down:
293 nCode = KEY_DOWN;
294 break;
295 case Qt::Key_Up:
296 nCode = KEY_UP;
297 break;
298 case Qt::Key_Left:
299 nCode = KEY_LEFT;
300 break;
301 case Qt::Key_Right:
302 nCode = KEY_RIGHT;
303 break;
304 case Qt::Key_Home:
305 nCode = KEY_HOME;
306 break;
307 case Qt::Key_End:
308 nCode = KEY_END;
309 break;
310 case Qt::Key_PageUp:
311 nCode = KEY_PAGEUP;
312 break;
313 case Qt::Key_PageDown:
314 nCode = KEY_PAGEDOWN;
315 break;
316 case Qt::Key_Return:
317 case Qt::Key_Enter:
318 nCode = KEY_RETURN;
319 break;
320 case Qt::Key_Escape:
321 nCode = KEY_ESCAPE;
322 break;
323 case Qt::Key_Tab:
324 // oddly enough, Qt doesn't send Shift-Tab event as 'Tab key pressed with Shift
325 // modifier' but as 'Backtab key pressed' (while its modifier bits are still
326 // set to Shift) -- so let's map both Key_Tab and Key_Backtab to VCL's KEY_TAB
327 case Qt::Key_Backtab:
328 nCode = KEY_TAB;
329 break;
330 case Qt::Key_Backspace:
331 nCode = KEY_BACKSPACE;
332 break;
333 case Qt::Key_Space:
334 nCode = KEY_SPACE;
335 break;
336 case Qt::Key_Insert:
337 nCode = KEY_INSERT;
338 break;
339 case Qt::Key_Delete:
340 nCode = KEY_DELETE;
341 break;
342 case Qt::Key_Plus:
343 nCode = KEY_ADD;
344 break;
345 case Qt::Key_Minus:
346 nCode = KEY_SUBTRACT;
347 break;
348 case Qt::Key_Asterisk:
349 nCode = KEY_MULTIPLY;
350 break;
351 case Qt::Key_Slash:
352 nCode = KEY_DIVIDE;
353 break;
354 case Qt::Key_Period:
355 nCode = KEY_POINT;
356 break;
357 case Qt::Key_Comma:
358 nCode = KEY_COMMA;
359 break;
360 case Qt::Key_Less:
361 nCode = KEY_LESS;
362 break;
363 case Qt::Key_Greater:
364 nCode = KEY_GREATER;
365 break;
366 case Qt::Key_Equal:
367 nCode = KEY_EQUAL;
368 break;
369 case Qt::Key_Find:
370 nCode = KEY_FIND;
371 break;
372 case Qt::Key_Menu:
373 nCode = KEY_CONTEXTMENU;
374 break;
375 case Qt::Key_Help:
376 nCode = KEY_HELP;
377 break;
378 case Qt::Key_Undo:
379 nCode = KEY_UNDO;
380 break;
381 case Qt::Key_Redo:
382 nCode = KEY_REPEAT;
383 break;
384 case Qt::Key_Cancel:
385 nCode = KEY_F11;
386 break;
387 case Qt::Key_AsciiTilde:
388 nCode = KEY_TILDE;
389 break;
390 case Qt::Key_QuoteLeft:
391 nCode = KEY_QUOTELEFT;
392 break;
393 case Qt::Key_BracketLeft:
394 nCode = KEY_BRACKETLEFT;
395 break;
396 case Qt::Key_BracketRight:
397 nCode = KEY_BRACKETRIGHT;
398 break;
399 case Qt::Key_Semicolon:
400 nCode = KEY_SEMICOLON;
401 break;
402 case Qt::Key_Copy:
403 nCode = KEY_COPY;
404 break;
405 case Qt::Key_Cut:
406 nCode = KEY_CUT;
407 break;
408 case Qt::Key_Open:
409 nCode = KEY_OPEN;
410 break;
411 case Qt::Key_Paste:
412 nCode = KEY_PASTE;
413 break;
417 return nCode;
420 void Qt5Widget::commitText(Qt5Frame& rFrame, const QString& aText)
422 SalExtTextInputEvent aInputEvent;
423 aInputEvent.mpTextAttr = nullptr;
424 aInputEvent.mnCursorFlags = 0;
425 aInputEvent.maText = toOUString(aText);
426 aInputEvent.mnCursorPos = aInputEvent.maText.getLength();
428 SolarMutexGuard aGuard;
429 vcl::DeletionListener aDel(&rFrame);
430 rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent);
431 if (!aDel.isDeleted())
432 rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr);
435 bool Qt5Widget::handleKeyEvent(Qt5Frame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent,
436 const ButtonKeyState eState)
438 sal_uInt16 nCode = GetKeyCode(pEvent->key(), pEvent->modifiers());
439 if (eState == ButtonKeyState::Pressed && nCode == 0 && pEvent->text().length() > 1
440 && rWidget.testAttribute(Qt::WA_InputMethodEnabled))
442 commitText(rFrame, pEvent->text());
443 pEvent->accept();
444 return true;
447 SalKeyEvent aEvent;
448 aEvent.mnCharCode = (pEvent->text().isEmpty() ? 0 : pEvent->text().at(0).unicode());
449 aEvent.mnRepeat = 0;
450 aEvent.mnCode = nCode;
451 aEvent.mnCode |= GetKeyModCode(pEvent->modifiers());
453 QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle);
455 bool bStopProcessingKey;
456 if (eState == ButtonKeyState::Pressed)
457 bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyInput, &aEvent);
458 else
459 bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyUp, &aEvent);
460 if (bStopProcessingKey)
461 pEvent->accept();
462 return bStopProcessingKey;
465 bool Qt5Widget::handleEvent(Qt5Frame& rFrame, const QWidget& rWidget, QEvent* pEvent)
467 if (pEvent->type() == QEvent::ShortcutOverride)
469 // ignore non-spontaneous QEvent::ShortcutOverride events,
470 // since such an extra event is sent e.g. with Orca screen reader enabled,
471 // so that two events of that kind (the "real one" and a non-spontaneous one)
472 // would otherwise be processed, resulting in duplicate input as 'handleKeyEvent'
473 // is called below (s. tdf#122053)
474 if (!pEvent->spontaneous())
476 return false;
479 // Accepted event disables shortcut activation,
480 // but enables keypress event.
481 // If event is not accepted and shortcut is successfully activated,
482 // KeyPress event is omitted.
484 // Instead of processing keyPressEvent, handle ShortcutOverride event,
485 // and if it's handled - disable the shortcut, it should have been activated.
486 // Don't process keyPressEvent generated after disabling shortcut since it was handled here.
487 // If event is not handled, don't accept it and let Qt activate related shortcut.
488 if (handleKeyEvent(rFrame, rWidget, static_cast<QKeyEvent*>(pEvent),
489 ButtonKeyState::Pressed))
490 return true;
492 return false;
495 bool Qt5Widget::event(QEvent* pEvent)
497 return handleEvent(m_rFrame, *this, pEvent) || QWidget::event(pEvent);
500 void Qt5Widget::keyReleaseEvent(QKeyEvent* pEvent)
502 if (!handleKeyReleaseEvent(m_rFrame, *this, pEvent))
503 QWidget::keyReleaseEvent(pEvent);
506 void Qt5Widget::focusInEvent(QFocusEvent*) { m_rFrame.CallCallback(SalEvent::GetFocus, nullptr); }
508 void Qt5Widget::focusOutEvent(QFocusEvent*)
510 endExtTextInput();
511 m_rFrame.CallCallback(SalEvent::LoseFocus, nullptr);
514 Qt5Widget::Qt5Widget(Qt5Frame& rFrame, Qt::WindowFlags f)
515 : QWidget(Q_NULLPTR, f)
516 , m_rFrame(rFrame)
517 , m_bNonEmptyIMPreeditSeen(false)
518 , m_nDeltaX(0)
519 , m_nDeltaY(0)
521 create();
522 setMouseTracking(true);
523 setFocusPolicy(Qt::StrongFocus);
526 static ExtTextInputAttr lcl_MapUndrelineStyle(QTextCharFormat::UnderlineStyle us)
528 switch (us)
530 case QTextCharFormat::NoUnderline:
531 return ExtTextInputAttr::NONE;
532 case QTextCharFormat::DotLine:
533 return ExtTextInputAttr::DottedUnderline;
534 case QTextCharFormat::DashDotDotLine:
535 case QTextCharFormat::DashDotLine:
536 return ExtTextInputAttr::DashDotUnderline;
537 case QTextCharFormat::WaveUnderline:
538 return ExtTextInputAttr::GrayWaveline;
539 default:
540 return ExtTextInputAttr::Underline;
544 void Qt5Widget::inputMethodEvent(QInputMethodEvent* pEvent)
546 if (!pEvent->commitString().isEmpty())
547 commitText(m_rFrame, pEvent->commitString());
548 else
550 SalExtTextInputEvent aInputEvent;
551 aInputEvent.mpTextAttr = nullptr;
552 aInputEvent.mnCursorFlags = 0;
553 aInputEvent.maText = toOUString(pEvent->preeditString());
554 aInputEvent.mnCursorPos = 0;
556 const sal_Int32 nLength = aInputEvent.maText.getLength();
557 const QList<QInputMethodEvent::Attribute>& rAttrList = pEvent->attributes();
558 std::vector<ExtTextInputAttr> aTextAttrs(std::max(sal_Int32(1), nLength),
559 ExtTextInputAttr::NONE);
560 aInputEvent.mpTextAttr = aTextAttrs.data();
562 for (int i = 0; i < rAttrList.size(); ++i)
564 const QInputMethodEvent::Attribute& rAttr = rAttrList.at(i);
565 switch (rAttr.type)
567 case QInputMethodEvent::TextFormat:
569 QTextCharFormat aCharFormat
570 = qvariant_cast<QTextFormat>(rAttr.value).toCharFormat();
571 if (aCharFormat.isValid())
573 ExtTextInputAttr aETIP
574 = lcl_MapUndrelineStyle(aCharFormat.underlineStyle());
575 if (aCharFormat.hasProperty(QTextFormat::BackgroundBrush))
576 aETIP |= ExtTextInputAttr::Highlight;
577 if (aCharFormat.fontStrikeOut())
578 aETIP |= ExtTextInputAttr::RedText;
579 for (int j = rAttr.start; j < rAttr.start + rAttr.length; j++)
580 aTextAttrs[j] = aETIP;
582 break;
584 case QInputMethodEvent::Cursor:
586 aInputEvent.mnCursorPos = rAttr.start;
587 if (rAttr.length == 0)
588 aInputEvent.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE;
589 break;
591 default:
592 SAL_WARN("vcl.qt5", "Unhandled QInputMethodEvent attribute: "
593 << static_cast<int>(rAttr.type));
594 break;
598 const bool bIsEmpty = aInputEvent.maText.isEmpty();
599 if (m_bNonEmptyIMPreeditSeen || !bIsEmpty)
601 SolarMutexGuard aGuard;
602 vcl::DeletionListener aDel(&m_rFrame);
603 m_rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent);
604 if (!aDel.isDeleted() && bIsEmpty)
605 m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr);
606 m_bNonEmptyIMPreeditSeen = !bIsEmpty;
610 pEvent->accept();
613 static bool lcl_retrieveSurrounding(sal_Int32& rPosition, sal_Int32& rAnchor, QString* pText,
614 QString* pSelection)
616 SolarMutexGuard aGuard;
617 vcl::Window* pFocusWin = Application::GetFocusWindow();
618 if (!pFocusWin)
619 return false;
621 uno::Reference<accessibility::XAccessibleEditableText> xText;
624 uno::Reference<accessibility::XAccessible> xAccessible(pFocusWin->GetAccessible());
625 if (xAccessible.is())
626 xText = FindFocusedEditableText(xAccessible->getAccessibleContext());
628 catch (const uno::Exception&)
630 TOOLS_WARN_EXCEPTION("vcl.qt5", "Exception in getting input method surrounding text");
633 if (xText.is())
635 rPosition = xText->getCaretPosition();
636 if (rPosition != -1)
638 if (pText)
639 *pText = toQString(xText->getText());
641 sal_Int32 nSelStart = xText->getSelectionStart();
642 sal_Int32 nSelEnd = xText->getSelectionEnd();
643 if (nSelStart == nSelEnd)
645 rAnchor = rPosition;
647 else
649 if (rPosition == nSelStart)
650 rAnchor = nSelEnd;
651 else
652 rAnchor = nSelStart;
653 if (pSelection)
654 *pSelection = toQString(xText->getSelectedText());
656 return true;
660 return false;
663 QVariant Qt5Widget::inputMethodQuery(Qt::InputMethodQuery property) const
665 switch (property)
667 case Qt::ImSurroundingText:
669 QString aText;
670 sal_Int32 nCursorPos, nAnchor;
671 if (lcl_retrieveSurrounding(nCursorPos, nAnchor, &aText, nullptr))
672 return QVariant(aText);
673 return QVariant();
675 case Qt::ImCursorPosition:
677 sal_Int32 nCursorPos, nAnchor;
678 if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr))
679 return QVariant(static_cast<int>(nCursorPos));
680 return QVariant();
682 case Qt::ImCursorRectangle:
684 const qreal fRatio = m_rFrame.devicePixelRatioF();
685 SalExtTextInputPosEvent aPosEvent;
686 m_rFrame.CallCallback(SalEvent::ExtTextInputPos, &aPosEvent);
687 return QVariant(QRect(aPosEvent.mnX / fRatio, aPosEvent.mnY / fRatio,
688 aPosEvent.mnWidth / fRatio, aPosEvent.mnHeight / fRatio));
690 case Qt::ImAnchorPosition:
692 sal_Int32 nCursorPos, nAnchor;
693 if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr))
694 return QVariant(static_cast<int>(nAnchor));
695 return QVariant();
697 case Qt::ImCurrentSelection:
699 QString aSelection;
700 sal_Int32 nCursorPos, nAnchor;
701 if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, &aSelection))
702 return QVariant(aSelection);
703 return QVariant();
705 default:
706 return QWidget::inputMethodQuery(property);
710 void Qt5Widget::endExtTextInput()
712 if (m_bNonEmptyIMPreeditSeen)
714 m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr);
715 m_bNonEmptyIMPreeditSeen = false;
719 void Qt5Widget::changeEvent(QEvent* pEvent)
721 switch (pEvent->type())
723 case QEvent::FontChange:
724 [[fallthrough]];
725 case QEvent::PaletteChange:
726 [[fallthrough]];
727 case QEvent::StyleChange:
729 auto* pSalInst(static_cast<Qt5Instance*>(GetSalData()->m_pInstance));
730 assert(pSalInst);
731 pSalInst->UpdateStyle(QEvent::FontChange == pEvent->type());
732 break;
734 default:
735 break;
737 QWidget::changeEvent(pEvent);
740 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */