1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 */
9
10 #include <Qt5Menu.hxx>
11 #include <Qt5Menu.moc>
12
13 #include <Qt5Frame.hxx>
14 #include <Qt5Instance.hxx>
15 #include <Qt5MainWindow.hxx>
16
17 #include <QtWidgets/QMenuBar>
18 #include <QtWidgets/QPushButton>
19
20 #include <vcl/svapp.hxx>
21 #include <sal/log.hxx>
22
23 #include <strings.hrc>
24 #include <bitmaps.hlst>
25
26 #include <vcl/floatwin.hxx>
27 #include <window.h>
28
Qt5Menu(bool bMenuBar)29 Qt5Menu::Qt5Menu(bool bMenuBar)
30 : mpVCLMenu(nullptr)
31 , mpParentSalMenu(nullptr)
32 , mpFrame(nullptr)
33 , mbMenuBar(bMenuBar)
34 , mpQMenuBar(nullptr)
35 , mpQMenu(nullptr)
36 , mpCloseButton(nullptr)
37 {
38 }
39
VisibleMenuBar()40 bool Qt5Menu::VisibleMenuBar() { return true; }
41
InsertMenuItem(Qt5MenuItem * pSalMenuItem,unsigned nPos)42 void Qt5Menu::InsertMenuItem(Qt5MenuItem* pSalMenuItem, unsigned nPos)
43 {
44 sal_uInt16 nId = pSalMenuItem->mnId;
45 OUString aText = mpVCLMenu->GetItemText(nId);
46 NativeItemText(aText);
47 vcl::KeyCode nAccelKey = mpVCLMenu->GetAccelKey(nId);
48
49 pSalMenuItem->mpAction.reset();
50 pSalMenuItem->mpMenu.reset();
51
52 if (mbMenuBar)
53 {
54 // top-level menu
55 if (mpQMenuBar)
56 {
57 QMenu* pQMenu = new QMenu(toQString(aText), nullptr);
58 pSalMenuItem->mpMenu.reset(pQMenu);
59
60 if ((nPos != MENU_APPEND)
61 && (static_cast<size_t>(nPos) < static_cast<size_t>(mpQMenuBar->actions().size())))
62 {
63 mpQMenuBar->insertMenu(mpQMenuBar->actions()[nPos], pQMenu);
64 }
65 else
66 {
67 mpQMenuBar->addMenu(pQMenu);
68 }
69
70 // correct parent menu for generated menu
71 if (pSalMenuItem->mpSubMenu)
72 {
73 pSalMenuItem->mpSubMenu->mpQMenu = pQMenu;
74 }
75
76 connect(pQMenu, &QMenu::aboutToShow, this,
77 [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); });
78 connect(pQMenu, &QMenu::aboutToHide, this,
79 [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); });
80 }
81 }
82 else
83 {
84 if (!mpQMenu)
85 {
86 // no QMenu set, instantiate own one
87 mpOwnedQMenu.reset(new QMenu);
88 mpQMenu = mpOwnedQMenu.get();
89 }
90
91 if (pSalMenuItem->mpSubMenu)
92 {
93 // submenu
94 QMenu* pQMenu = new QMenu(toQString(aText), nullptr);
95 pSalMenuItem->mpMenu.reset(pQMenu);
96
97 if ((nPos != MENU_APPEND)
98 && (static_cast<size_t>(nPos) < static_cast<size_t>(mpQMenu->actions().size())))
99 {
100 mpQMenu->insertMenu(mpQMenu->actions()[nPos], pQMenu);
101 }
102 else
103 {
104 mpQMenu->addMenu(pQMenu);
105 }
106
107 // correct parent menu for generated menu
108 pSalMenuItem->mpSubMenu->mpQMenu = pQMenu;
109
110 ReinitializeActionGroup(nPos);
111
112 // clear all action groups since menu is recreated
113 pSalMenuItem->mpSubMenu->ResetAllActionGroups();
114
115 connect(pQMenu, &QMenu::aboutToShow, this,
116 [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); });
117 connect(pQMenu, &QMenu::aboutToHide, this,
118 [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); });
119 }
120 else
121 {
122 if (pSalMenuItem->mnType == MenuItemType::SEPARATOR)
123 {
124 QAction* pAction = new QAction(nullptr);
125 pSalMenuItem->mpAction.reset(pAction);
126 pAction->setSeparator(true);
127
128 if ((nPos != MENU_APPEND)
129 && (static_cast<size_t>(nPos) < static_cast<size_t>(mpQMenu->actions().size())))
130 {
131 mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction);
132 }
133 else
134 {
135 mpQMenu->addAction(pAction);
136 }
137
138 ReinitializeActionGroup(nPos);
139 }
140 else
141 {
142 // leaf menu
143 QAction* pAction = new QAction(toQString(aText), nullptr);
144 pSalMenuItem->mpAction.reset(pAction);
145
146 if ((nPos != MENU_APPEND)
147 && (static_cast<size_t>(nPos) < static_cast<size_t>(mpQMenu->actions().size())))
148 {
149 mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction);
150 }
151 else
152 {
153 mpQMenu->addAction(pAction);
154 }
155
156 ReinitializeActionGroup(nPos);
157
158 UpdateActionGroupItem(pSalMenuItem);
159
160 const Qt5Frame* pFrame = GetFrame();
161 if (pFrame)
162 pAction->setShortcut(toQString(nAccelKey.GetName(pFrame->GetWindow())));
163
164 connect(pAction, &QAction::triggered, this,
165 [pSalMenuItem] { slotMenuTriggered(pSalMenuItem); });
166 }
167 }
168 }
169
170 QAction* pAction = pSalMenuItem->getAction();
171 if (pAction)
172 {
173 pAction->setEnabled(pSalMenuItem->mbEnabled);
174 pAction->setVisible(pSalMenuItem->mbVisible);
175 }
176 }
177
ReinitializeActionGroup(unsigned nPos)178 void Qt5Menu::ReinitializeActionGroup(unsigned nPos)
179 {
180 const unsigned nCount = GetItemCount();
181
182 if (nCount == 0)
183 {
184 return;
185 }
186
187 if (nPos == MENU_APPEND)
188 {
189 nPos = nCount - 1;
190 }
191 else if (nPos >= nCount)
192 {
193 return;
194 }
195
196 Qt5MenuItem* pPrevItem = (nPos > 0) ? GetItemAtPos(nPos - 1) : nullptr;
197 Qt5MenuItem* pCurrentItem = GetItemAtPos(nPos);
198 Qt5MenuItem* pNextItem = (nPos < nCount - 1) ? GetItemAtPos(nPos + 1) : nullptr;
199
200 if (pCurrentItem->mnType == MenuItemType::SEPARATOR)
201 {
202 pCurrentItem->mpActionGroup.reset();
203
204 // if it's inserted into middle of existing group, split it into two groups:
205 // first goes original group, after separator goes new group
206 if (pPrevItem && pPrevItem->mpActionGroup && pNextItem && pNextItem->mpActionGroup
207 && (pPrevItem->mpActionGroup == pNextItem->mpActionGroup))
208 {
209 std::shared_ptr<QActionGroup> pFirstActionGroup = pPrevItem->mpActionGroup;
210 std::shared_ptr<QActionGroup> pSecondActionGroup(new QActionGroup(nullptr));
211 pSecondActionGroup->setExclusive(true);
212
213 auto actions = pFirstActionGroup->actions();
214
215 for (unsigned idx = nPos + 1; idx < nCount; ++idx)
216 {
217 Qt5MenuItem* pModifiedItem = GetItemAtPos(idx);
218
219 if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup))
220 {
221 break;
222 }
223
224 pModifiedItem->mpActionGroup = pSecondActionGroup;
225 auto action = pModifiedItem->getAction();
226
227 if (actions.contains(action))
228 {
229 pFirstActionGroup->removeAction(action);
230 pSecondActionGroup->addAction(action);
231 }
232 }
233 }
234 }
235 else
236 {
237 if (!pCurrentItem->mpActionGroup)
238 {
239 // unless element is inserted between two separators, or a separator and an end of vector, use neighbouring group since it's shared
240 if (pPrevItem && pPrevItem->mpActionGroup)
241 {
242 pCurrentItem->mpActionGroup = pPrevItem->mpActionGroup;
243 }
244 else if (pNextItem && pNextItem->mpActionGroup)
245 {
246 pCurrentItem->mpActionGroup = pNextItem->mpActionGroup;
247 }
248 else
249 {
250 pCurrentItem->mpActionGroup.reset(new QActionGroup(nullptr));
251 pCurrentItem->mpActionGroup->setExclusive(true);
252 }
253 }
254
255 // if there's also a different group after this element, merge it
256 if (pNextItem && pNextItem->mpActionGroup
257 && (pCurrentItem->mpActionGroup != pNextItem->mpActionGroup))
258 {
259 auto pFirstCheckedAction = pCurrentItem->mpActionGroup->checkedAction();
260 auto pSecondCheckedAction = pNextItem->mpActionGroup->checkedAction();
261 auto actions = pNextItem->mpActionGroup->actions();
262
263 // first move all actions from second group to first one, and if first group already has checked action,
264 // and second group also has a checked action, uncheck action from second group
265 for (auto action : actions)
266 {
267 pNextItem->mpActionGroup->removeAction(action);
268
269 if (pFirstCheckedAction && pSecondCheckedAction && (action == pSecondCheckedAction))
270 {
271 action->setChecked(false);
272 }
273
274 pCurrentItem->mpActionGroup->addAction(action);
275 }
276
277 // now replace all pointers to second group with pointers to first group
278 for (unsigned idx = nPos + 1; idx < nCount; ++idx)
279 {
280 Qt5MenuItem* pModifiedItem = GetItemAtPos(idx);
281
282 if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup))
283 {
284 break;
285 }
286
287 pModifiedItem->mpActionGroup = pCurrentItem->mpActionGroup;
288 }
289 }
290 }
291 }
292
ResetAllActionGroups()293 void Qt5Menu::ResetAllActionGroups()
294 {
295 for (unsigned nItem = 0; nItem < GetItemCount(); ++nItem)
296 {
297 Qt5MenuItem* pSalMenuItem = GetItemAtPos(nItem);
298 pSalMenuItem->mpActionGroup.reset();
299 }
300 }
301
UpdateActionGroupItem(const Qt5MenuItem * pSalMenuItem)302 void Qt5Menu::UpdateActionGroupItem(const Qt5MenuItem* pSalMenuItem)
303 {
304 QAction* pAction = pSalMenuItem->getAction();
305 if (!pAction)
306 return;
307
308 bool bChecked = mpVCLMenu->IsItemChecked(pSalMenuItem->mnId);
309 MenuItemBits itemBits = mpVCLMenu->GetItemBits(pSalMenuItem->mnId);
310
311 if (itemBits & MenuItemBits::RADIOCHECK)
312 {
313 pAction->setCheckable(true);
314
315 if (pSalMenuItem->mpActionGroup)
316 {
317 pSalMenuItem->mpActionGroup->addAction(pAction);
318 }
319
320 pAction->setChecked(bChecked);
321 }
322 else
323 {
324 pAction->setActionGroup(nullptr);
325
326 if (itemBits & MenuItemBits::CHECKABLE)
327 {
328 pAction->setCheckable(true);
329 pAction->setChecked(bChecked);
330 }
331 else
332 {
333 pAction->setChecked(false);
334 pAction->setCheckable(false);
335 }
336 }
337 }
338
InsertItem(SalMenuItem * pSalMenuItem,unsigned nPos)339 void Qt5Menu::InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos)
340 {
341 SolarMutexGuard aGuard;
342 Qt5MenuItem* pItem = static_cast<Qt5MenuItem*>(pSalMenuItem);
343
344 if (nPos == MENU_APPEND)
345 maItems.push_back(pItem);
346 else
347 maItems.insert(maItems.begin() + nPos, pItem);
348
349 pItem->mpParentMenu = this;
350
351 InsertMenuItem(pItem, nPos);
352 }
353
RemoveItem(unsigned nPos)354 void Qt5Menu::RemoveItem(unsigned nPos)
355 {
356 SolarMutexGuard aGuard;
357
358 if (nPos < maItems.size())
359 {
360 Qt5MenuItem* pItem = maItems[nPos];
361 pItem->mpAction.reset();
362 pItem->mpMenu.reset();
363
364 maItems.erase(maItems.begin() + nPos);
365
366 // Recalculate action groups if necessary:
367 // if separator between two QActionGroups was removed,
368 // it may be needed to merge them
369 if (nPos > 0)
370 {
371 ReinitializeActionGroup(nPos - 1);
372 }
373 }
374 }
375
SetSubMenu(SalMenuItem * pSalMenuItem,SalMenu * pSubMenu,unsigned nPos)376 void Qt5Menu::SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos)
377 {
378 SolarMutexGuard aGuard;
379 Qt5MenuItem* pItem = static_cast<Qt5MenuItem*>(pSalMenuItem);
380 Qt5Menu* pQSubMenu = static_cast<Qt5Menu*>(pSubMenu);
381
382 pItem->mpSubMenu = pQSubMenu;
383 // at this point the pointer to parent menu may be outdated, update it too
384 pItem->mpParentMenu = this;
385
386 if (pQSubMenu != nullptr)
387 {
388 pQSubMenu->mpParentSalMenu = this;
389 pQSubMenu->mpQMenu = pItem->mpMenu.get();
390 }
391
392 // if it's not a menu bar item, then convert it to corresponding item if type if necessary.
393 // If submenu is present and it's an action, convert it to menu.
394 // If submenu is not present and it's a menu, convert it to action.
395 // It may be fine to proceed in any case, but by skipping other cases
396 // amount of unneeded actions taken should be reduced.
397 if (pItem->mpParentMenu->mbMenuBar || (pQSubMenu && pItem->mpMenu)
398 || ((!pQSubMenu) && pItem->mpAction))
399 {
400 return;
401 }
402
403 InsertMenuItem(pItem, nPos);
404 }
405
SetFrame(const SalFrame * pFrame)406 void Qt5Menu::SetFrame(const SalFrame* pFrame)
407 {
408 auto* pSalInst(static_cast<Qt5Instance*>(GetSalData()->m_pInstance));
409 assert(pSalInst);
410 if (!pSalInst->IsMainThread())
411 {
412 pSalInst->RunInMainThread([this, pFrame]() { SetFrame(pFrame); });
413 return;
414 }
415
416 SolarMutexGuard aGuard;
417 assert(mbMenuBar);
418 mpFrame = const_cast<Qt5Frame*>(static_cast<const Qt5Frame*>(pFrame));
419
420 mpFrame->SetMenu(this);
421
422 Qt5MainWindow* pMainWindow = mpFrame->GetTopLevelWindow();
423 if (pMainWindow)
424 {
425 mpQMenuBar = pMainWindow->menuBar();
426 if (mpQMenuBar)
427 {
428 mpQMenuBar->clear();
429 QPushButton* pButton
430 = static_cast<QPushButton*>(mpQMenuBar->cornerWidget(Qt::TopRightCorner));
431 if (pButton && ((mpCloseButton != pButton) || !maCloseButtonConnection))
432 {
433 maCloseButtonConnection
434 = connect(pButton, &QPushButton::clicked, this, &Qt5Menu::slotCloseDocument);
435 mpCloseButton = pButton;
436 }
437 }
438
439 mpQMenu = nullptr;
440
441 DoFullMenuUpdate(mpVCLMenu);
442 }
443 }
444
DoFullMenuUpdate(Menu * pMenuBar)445 void Qt5Menu::DoFullMenuUpdate(Menu* pMenuBar)
446 {
447 // clear action groups since menu is rebuilt
448 ResetAllActionGroups();
449 ShowCloseButton(false);
450
451 for (sal_Int32 nItem = 0; nItem < static_cast<sal_Int32>(GetItemCount()); nItem++)
452 {
453 Qt5MenuItem* pSalMenuItem = GetItemAtPos(nItem);
454 InsertMenuItem(pSalMenuItem, nItem);
455 SetItemImage(nItem, pSalMenuItem, pSalMenuItem->maImage);
456 const bool bShowDisabled
457 = bool(pMenuBar->GetMenuFlags() & MenuFlags::AlwaysShowDisabledEntries)
458 || !bool(pMenuBar->GetMenuFlags() & MenuFlags::HideDisabledEntries);
459 const bool bVisible = bShowDisabled || mpVCLMenu->IsItemEnabled(pSalMenuItem->mnId);
460 pSalMenuItem->getAction()->setVisible(bVisible);
461
462 if (pSalMenuItem->mpSubMenu != nullptr)
463 {
464 pMenuBar->HandleMenuActivateEvent(pSalMenuItem->mpSubMenu->GetMenu());
465 pSalMenuItem->mpSubMenu->DoFullMenuUpdate(pMenuBar);
466 pMenuBar->HandleMenuDeActivateEvent(pSalMenuItem->mpSubMenu->GetMenu());
467 }
468 }
469 }
470
ShowItem(unsigned nPos,bool bShow)471 void Qt5Menu::ShowItem(unsigned nPos, bool bShow)
472 {
473 if (nPos < maItems.size())
474 {
475 Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos);
476 QAction* pAction = pSalMenuItem->getAction();
477 if (pAction)
478 pAction->setVisible(bShow);
479 pSalMenuItem->mbVisible = bShow;
480 }
481 }
482
SetItemBits(unsigned nPos,MenuItemBits)483 void Qt5Menu::SetItemBits(unsigned nPos, MenuItemBits)
484 {
485 if (nPos < maItems.size())
486 {
487 Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos);
488 UpdateActionGroupItem(pSalMenuItem);
489 }
490 }
491
CheckItem(unsigned nPos,bool bChecked)492 void Qt5Menu::CheckItem(unsigned nPos, bool bChecked)
493 {
494 if (nPos < maItems.size())
495 {
496 Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos);
497 QAction* pAction = pSalMenuItem->getAction();
498 if (pAction)
499 {
500 pAction->setCheckable(true);
501 pAction->setChecked(bChecked);
502 }
503 }
504 }
505
EnableItem(unsigned nPos,bool bEnable)506 void Qt5Menu::EnableItem(unsigned nPos, bool bEnable)
507 {
508 if (nPos < maItems.size())
509 {
510 Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos);
511 QAction* pAction = pSalMenuItem->getAction();
512 if (pAction)
513 pAction->setEnabled(bEnable);
514 pSalMenuItem->mbEnabled = bEnable;
515 }
516 }
517
SetItemText(unsigned,SalMenuItem * pItem,const OUString & rText)518 void Qt5Menu::SetItemText(unsigned, SalMenuItem* pItem, const OUString& rText)
519 {
520 Qt5MenuItem* pSalMenuItem = static_cast<Qt5MenuItem*>(pItem);
521 QAction* pAction = pSalMenuItem->getAction();
522 if (pAction)
523 {
524 OUString aText(rText);
525 NativeItemText(aText);
526 pAction->setText(toQString(aText));
527 }
528 }
529
SetItemImage(unsigned,SalMenuItem * pItem,const Image & rImage)530 void Qt5Menu::SetItemImage(unsigned, SalMenuItem* pItem, const Image& rImage)
531 {
532 Qt5MenuItem* pSalMenuItem = static_cast<Qt5MenuItem*>(pItem);
533
534 // Save new image to use it in DoFullMenuUpdate
535 pSalMenuItem->maImage = rImage;
536
537 QAction* pAction = pSalMenuItem->getAction();
538 if (!pAction)
539 return;
540
541 pAction->setIcon(QPixmap::fromImage(toQImage(rImage)));
542 }
543
SetAccelerator(unsigned,SalMenuItem * pItem,const vcl::KeyCode &,const OUString & rText)544 void Qt5Menu::SetAccelerator(unsigned, SalMenuItem* pItem, const vcl::KeyCode&,
545 const OUString& rText)
546 {
547 Qt5MenuItem* pSalMenuItem = static_cast<Qt5MenuItem*>(pItem);
548 QAction* pAction = pSalMenuItem->getAction();
549 if (pAction)
550 pAction->setShortcut(QKeySequence(toQString(rText), QKeySequence::PortableText));
551 }
552
GetSystemMenuData(SystemMenuData *)553 void Qt5Menu::GetSystemMenuData(SystemMenuData*) {}
554
GetTopLevel()555 Qt5Menu* Qt5Menu::GetTopLevel()
556 {
557 Qt5Menu* pMenu = this;
558 while (pMenu->mpParentSalMenu)
559 pMenu = pMenu->mpParentSalMenu;
560 return pMenu;
561 }
562
ShowMenuBar(bool bVisible)563 void Qt5Menu::ShowMenuBar(bool bVisible)
564 {
565 if (mpQMenuBar)
566 mpQMenuBar->setVisible(bVisible);
567 }
568
GetFrame() const569 const Qt5Frame* Qt5Menu::GetFrame() const
570 {
571 SolarMutexGuard aGuard;
572 const Qt5Menu* pMenu = this;
573 while (pMenu && !pMenu->mpFrame)
574 pMenu = pMenu->mpParentSalMenu;
575 return pMenu ? pMenu->mpFrame : nullptr;
576 }
577
slotMenuTriggered(Qt5MenuItem * pQItem)578 void Qt5Menu::slotMenuTriggered(Qt5MenuItem* pQItem)
579 {
580 if (pQItem)
581 {
582 Qt5Menu* pSalMenu = pQItem->mpParentMenu;
583 Qt5Menu* pTopLevel = pSalMenu->GetTopLevel();
584
585 Menu* pMenu = pSalMenu->GetMenu();
586 auto mnId = pQItem->mnId;
587
588 // HACK to allow HandleMenuCommandEvent to "not-set" the checked button
589 // LO expects a signal before an item state change, so reset the check item
590 if (pQItem->mpAction->isCheckable()
591 && (!pQItem->mpActionGroup || pQItem->mpActionGroup->actions().size() <= 1))
592 pQItem->mpAction->setChecked(!pQItem->mpAction->isChecked());
593 pTopLevel->GetMenu()->HandleMenuCommandEvent(pMenu, mnId);
594 }
595 }
596
slotMenuAboutToShow(Qt5MenuItem * pQItem)597 void Qt5Menu::slotMenuAboutToShow(Qt5MenuItem* pQItem)
598 {
599 if (pQItem)
600 {
601 Qt5Menu* pSalMenu = pQItem->mpSubMenu;
602 Qt5Menu* pTopLevel = pSalMenu->GetTopLevel();
603
604 Menu* pMenu = pSalMenu->GetMenu();
605
606 // following function may update the menu
607 pTopLevel->GetMenu()->HandleMenuActivateEvent(pMenu);
608 }
609 }
610
slotMenuAboutToHide(Qt5MenuItem * pQItem)611 void Qt5Menu::slotMenuAboutToHide(Qt5MenuItem* pQItem)
612 {
613 if (pQItem)
614 {
615 Qt5Menu* pSalMenu = pQItem->mpSubMenu;
616 Qt5Menu* pTopLevel = pSalMenu->GetTopLevel();
617
618 Menu* pMenu = pSalMenu->GetMenu();
619
620 pTopLevel->GetMenu()->HandleMenuDeActivateEvent(pMenu);
621 }
622 }
623
NativeItemText(OUString & rItemText)624 void Qt5Menu::NativeItemText(OUString& rItemText)
625 {
626 // preserve literal '&'s in menu texts
627 rItemText = rItemText.replaceAll("&", "&&");
628
629 rItemText = rItemText.replace('~', '&');
630 }
631
slotCloseDocument()632 void Qt5Menu::slotCloseDocument()
633 {
634 MenuBar* pVclMenuBar = static_cast<MenuBar*>(mpVCLMenu.get());
635 if (pVclMenuBar)
636 Application::PostUserEvent(pVclMenuBar->GetCloseButtonClickHdl());
637 }
638
ShowCloseButton(bool bShow)639 void Qt5Menu::ShowCloseButton(bool bShow)
640 {
641 if (!mpQMenuBar)
642 return;
643
644 QPushButton* pButton = static_cast<QPushButton*>(mpQMenuBar->cornerWidget(Qt::TopRightCorner));
645 if (!pButton)
646 {
647 QIcon aIcon;
648 if (QIcon::hasThemeIcon("window-close-symbolic"))
649 aIcon = QIcon::fromTheme("window-close-symbolic");
650 else
651 aIcon = QIcon(
652 QPixmap::fromImage((toQImage(Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC)))));
653 pButton = new QPushButton(mpQMenuBar);
654 pButton->setIcon(aIcon);
655 pButton->setFlat(true);
656 pButton->setFocusPolicy(Qt::NoFocus);
657 pButton->setToolTip(toQString(VclResId(SV_HELPTEXT_CLOSEDOCUMENT)));
658 mpQMenuBar->setCornerWidget(pButton, Qt::TopRightCorner);
659 maCloseButtonConnection
660 = connect(pButton, &QPushButton::clicked, this, &Qt5Menu::slotCloseDocument);
661 mpCloseButton = pButton;
662 }
663
664 if (bShow)
665 pButton->show();
666 else
667 pButton->hide();
668 }
669
ShowNativePopupMenu(FloatingWindow *,const tools::Rectangle &,FloatWinPopupFlags nFlags)670 bool Qt5Menu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&,
671 FloatWinPopupFlags nFlags)
672 {
673 assert(mpQMenu);
674 DoFullMenuUpdate(mpVCLMenu);
675 mpQMenu->setTearOffEnabled(bool(nFlags & FloatWinPopupFlags::AllowTearOff));
676
677 const QPoint aPos = QCursor::pos();
678 mpQMenu->exec(aPos);
679
680 return true;
681 }
682
Qt5MenuItem(const SalItemParams * pItemData)683 Qt5MenuItem::Qt5MenuItem(const SalItemParams* pItemData)
684 : mpParentMenu(nullptr)
685 , mpSubMenu(nullptr)
686 , mnId(pItemData->nId)
687 , mnType(pItemData->eType)
688 , mbVisible(true)
689 , mbEnabled(true)
690 , maImage(pItemData->aImage)
691 {
692 }
693
getAction() const694 QAction* Qt5MenuItem::getAction() const
695 {
696 if (mpMenu)
697 return mpMenu->menuAction();
698 if (mpAction)
699 return mpAction.get();
700 return nullptr;
701 }
702
703 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
704