vcl/inc/qt5/Qt5Menu.hxx |    8 +
 vcl/qt5/Qt5Menu.cxx     |  249 ++++++++++++++++++++++++++++++++++--------------
 2 files changed, 188 insertions(+), 69 deletions(-)

New commits:
commit 517af5bbd0cd659f09afd33a80f0d6c72016fafe
Author:     Aleksei Nikiforov <darktemp...@basealt.ru>
AuthorDate: Thu Nov 22 12:27:26 2018 +0300
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Fri Dec 14 14:27:42 2018 +0100

    tdf#121417 Allow dynamic menu changes for Qt5 and KDE5 interfaces
    
    Separate HandleMenuActivateEvent function call from HandleMenuCommandEvent 
function call
    since first one might update some of menus. Also add call to 
HandleMenuDeActivateEvent function.
    
    Delete action with Qt5MenuItem to reflect the change in actual menu.
    
    Also update underlying qt-based menu from Qt5Menu::InsertItem function.
    
    And update Qt5Menu::SetItemImage to work with different types of 
descendants of SalBitmap.
    This code is shared between Qt5 and KDE5 plugins, but KDE5 plugin uses 
SvpSalBitmap instead of Qt5Bitmap.
    New image conversion process is borrowed from GTK plugin code.
    This approach is used in order to properly process transparency channel if 
it's present, and it is present usually.
    
    This change also fixes tdf#120789.
    
    Change-Id: Ifdc64c3e5d80782955b52e2da8fcff4844d2dc25
    Reviewed-on: https://gerrit.libreoffice.org/63862
    Tested-by: Jenkins
    Reviewed-by: Katarina Behrens <katarina.behr...@cib.de>
    
    Move menu item insertion into separate function
    
    Change-Id: I721910bbbd558827e9a5de1f8763426b460f08fa
    Reviewed-on: https://gerrit.libreoffice.org/63861
    Tested-by: Jenkins
    Reviewed-by: Katarina Behrens <katarina.behr...@cib.de>
    
    Fix menu insertion to specified position
    
    Change-Id: I61f870010003fae98d792f95d7fdac0e59d4305c
    Reviewed-on: https://gerrit.libreoffice.org/63885
    Tested-by: Jenkins
    Reviewed-by: Samuel Mehrbrodt <samuel.mehrbr...@cib.de>
    
    loplugin:override
    
    Change-Id: Ia45b5f7c126c082d8f3835c3c3529a34a9e20975
    Reviewed-on: https://gerrit.libreoffice.org/65149
    Tested-by: Jenkins
    Reviewed-by: Aleksei Nikiforov <darktemp...@basealt.ru>
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/vcl/inc/qt5/Qt5Menu.hxx b/vcl/inc/qt5/Qt5Menu.hxx
index e31c44fa8b55..43641f023542 100644
--- a/vcl/inc/qt5/Qt5Menu.hxx
+++ b/vcl/inc/qt5/Qt5Menu.hxx
@@ -12,6 +12,7 @@
 #include <salmenu.hxx>
 
 class MenuItemList;
+class QActionGroup;
 class QMenu;
 class QMenuBar;
 class Qt5MenuItem;
@@ -27,10 +28,14 @@ private:
     Qt5Frame* mpFrame;
     bool mbMenuBar;
     QMenuBar* mpQMenuBar;
+    QMenu* mpQMenu;
+    QActionGroup* mpQActionGroup;
 
     void DoFullMenuUpdate(Menu* pMenuBar, QMenu* pParentMenu = nullptr);
     static void NativeItemText(OUString& rItemText);
 
+    QMenu* InsertMenuItem(Qt5MenuItem* pSalMenuItem, unsigned nPos);
+
 public:
     Qt5Menu(bool bMenuBar);
     virtual ~Qt5Menu() override;
@@ -64,12 +69,15 @@ Q_SIGNALS:
 
 private slots:
     static void slotMenuTriggered(Qt5MenuItem* pQItem);
+    static void slotMenuAboutToShow(Qt5MenuItem* pQItem);
+    static void slotMenuAboutToHide(Qt5MenuItem* pQItem);
 };
 
 class Qt5MenuItem : public SalMenuItem
 {
 public:
     Qt5MenuItem(const SalItemParams*);
+    virtual ~Qt5MenuItem() override;
 
     Qt5Menu* mpParentMenu; // The menu into which this menu item is inserted
     Qt5Menu* mpSubMenu; // Submenu of this item (if defined)
diff --git a/vcl/qt5/Qt5Menu.cxx b/vcl/qt5/Qt5Menu.cxx
index c3228bdd90c0..8acaf1e5e410 100644
--- a/vcl/qt5/Qt5Menu.cxx
+++ b/vcl/qt5/Qt5Menu.cxx
@@ -10,6 +10,7 @@
 #include <Qt5Frame.hxx>
 #include <Qt5MainWindow.hxx>
 #include <Qt5Bitmap.hxx>
+#include <Qt5Tools.hxx>
 #include <Qt5Menu.hxx>
 #include <Qt5Menu.moc>
 
@@ -17,12 +18,17 @@
 
 #include <vcl/svapp.hxx>
 #include <sal/log.hxx>
+#include <vcl/pngwrite.hxx>
+#include <tools/stream.hxx>
 
 Qt5Menu::Qt5Menu(bool bMenuBar)
     : mpVCLMenu(nullptr)
     , mpParentSalMenu(nullptr)
     , mpFrame(nullptr)
     , mbMenuBar(bMenuBar)
+    , mpQMenuBar(nullptr)
+    , mpQMenu(nullptr)
+    , mpQActionGroup(nullptr)
 {
     connect(this, &Qt5Menu::setFrameSignal, this, &Qt5Menu::SetFrame, 
Qt::BlockingQueuedConnection);
 }
@@ -31,6 +37,129 @@ Qt5Menu::~Qt5Menu() { maItems.clear(); }
 
 bool Qt5Menu::VisibleMenuBar() { return true; }
 
+QMenu* Qt5Menu::InsertMenuItem(Qt5MenuItem* pSalMenuItem, unsigned nPos)
+{
+    QMenu* pQMenu = mpQMenu;
+    sal_uInt16 nId = pSalMenuItem->mnId;
+    OUString aText = mpVCLMenu->GetItemText(nId);
+    NativeItemText(aText);
+    vcl::KeyCode nAccelKey = mpVCLMenu->GetAccelKey(nId);
+    bool bChecked = mpVCLMenu->IsItemChecked(nId);
+    MenuItemBits itemBits = mpVCLMenu->GetItemBits(nId);
+
+    if (mbMenuBar)
+    {
+        // top-level menu
+        if (mpQMenuBar)
+        {
+            if ((nPos != MENU_APPEND)
+                && (static_cast<size_t>(nPos) < 
static_cast<size_t>(mpQMenuBar->actions().size())))
+            {
+                pQMenu = new QMenu(toQString(aText), mpQMenuBar);
+                mpQMenuBar->insertMenu(mpQMenuBar->actions()[nPos], pQMenu);
+            }
+            else
+            {
+                pQMenu = mpQMenuBar->addMenu(toQString(aText));
+            }
+
+            connect(pQMenu, &QMenu::aboutToShow, this,
+                    [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); });
+            connect(pQMenu, &QMenu::aboutToHide, this,
+                    [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); });
+        }
+    }
+    else if (pQMenu)
+    {
+        if (pSalMenuItem->mpSubMenu)
+        {
+            // submenu
+            if ((nPos != MENU_APPEND)
+                && (static_cast<size_t>(nPos) < 
static_cast<size_t>(pQMenu->actions().size())))
+            {
+                QMenu* pTempQMenu = new QMenu(toQString(aText), pQMenu);
+                pQMenu->insertMenu(pQMenu->actions()[nPos], pTempQMenu);
+                pQMenu = pTempQMenu;
+            }
+            else
+            {
+                pQMenu = pQMenu->addMenu(toQString(aText));
+            }
+
+            mpQActionGroup = new QActionGroup(pQMenu);
+
+            connect(pQMenu, &QMenu::aboutToShow, this,
+                    [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); });
+            connect(pQMenu, &QMenu::aboutToHide, this,
+                    [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); });
+        }
+        else
+        {
+            delete pSalMenuItem->mpAction;
+
+            if (pSalMenuItem->mnType == MenuItemType::SEPARATOR)
+            {
+                if ((nPos != MENU_APPEND)
+                    && (static_cast<size_t>(nPos) < 
static_cast<size_t>(pQMenu->actions().size())))
+                {
+                    pSalMenuItem->mpAction = 
pQMenu->insertSeparator(pQMenu->actions()[nPos]);
+                }
+                else
+                {
+                    pSalMenuItem->mpAction = pQMenu->addSeparator();
+                }
+            }
+            else
+            {
+                // leaf menu
+                QAction* pAction = nullptr;
+
+                if ((nPos != MENU_APPEND)
+                    && (static_cast<size_t>(nPos) < 
static_cast<size_t>(pQMenu->actions().size())))
+                {
+                    pAction = new QAction(toQString(aText), pQMenu);
+                    pQMenu->insertAction(pQMenu->actions()[nPos], pAction);
+                }
+                else
+                {
+                    pAction = pQMenu->addAction(toQString(aText));
+                }
+
+                pSalMenuItem->mpAction = pAction;
+                
pAction->setShortcut(toQString(nAccelKey.GetName(GetFrame()->GetWindow())));
+
+                if (itemBits & MenuItemBits::CHECKABLE)
+                {
+                    pAction->setCheckable(true);
+                    pAction->setChecked(bChecked);
+                }
+                else if (itemBits & MenuItemBits::RADIOCHECK)
+                {
+                    pAction->setCheckable(true);
+                    if (!mpQActionGroup)
+                    {
+                        mpQActionGroup = new QActionGroup(pQMenu);
+                        mpQActionGroup->setExclusive(true);
+                    }
+                    // NOTE: QActionGroup support may need improvement
+                    // if menu item is added not to the end of menu,
+                    // it may be needed to add new item to QActionGroup 
different from last created one for this menu
+                    mpQActionGroup->addAction(pAction);
+                    pAction->setChecked(bChecked);
+                }
+
+                pAction->setEnabled(pSalMenuItem->mbEnabled);
+                pAction->setVisible(pSalMenuItem->mbVisible);
+
+                connect(pAction, &QAction::triggered, this,
+                        [pSalMenuItem] { slotMenuTriggered(pSalMenuItem); });
+            }
+        }
+    }
+
+    return pQMenu;
+}
+
 void Qt5Menu::InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos)
 {
     SolarMutexGuard aGuard;
@@ -42,6 +171,8 @@ void Qt5Menu::InsertItem(SalMenuItem* pSalMenuItem, unsigned 
nPos)
         maItems.insert(maItems.begin() + nPos, pItem);
 
     pItem->mpParentMenu = this;
+
+    InsertMenuItem(pItem, nPos);
 }
 
 void Qt5Menu::RemoveItem(unsigned nPos)
@@ -88,70 +219,16 @@ void Qt5Menu::SetFrame(const SalFrame* pFrame)
 
 void Qt5Menu::DoFullMenuUpdate(Menu* pMenuBar, QMenu* pParentMenu)
 {
-    Menu* pVCLMenu = mpVCLMenu;
+    mpQMenu = pParentMenu;
 
     if (mbMenuBar && mpQMenuBar)
         mpQMenuBar->clear();
-    QActionGroup* pQAG = nullptr;
+    mpQActionGroup = nullptr;
 
     for (sal_Int32 nItem = 0; nItem < static_cast<sal_Int32>(GetItemCount()); 
nItem++)
     {
         Qt5MenuItem* pSalMenuItem = GetItemAtPos(nItem);
-        sal_uInt16 nId = pSalMenuItem->mnId;
-        OUString aText = pVCLMenu->GetItemText(nId);
-        QMenu* pQMenu = pParentMenu;
-        NativeItemText(aText);
-        vcl::KeyCode nAccelKey = pVCLMenu->GetAccelKey(nId);
-        bool bChecked = pVCLMenu->IsItemChecked(nId);
-        MenuItemBits itemBits = pVCLMenu->GetItemBits(nId);
-
-        if (mbMenuBar && mpQMenuBar)
-            // top-level menu
-            pQMenu = mpQMenuBar->addMenu(toQString(aText));
-        else
-        {
-            if (pSalMenuItem->mpSubMenu)
-            {
-                // submenu
-                pQMenu = pQMenu->addMenu(toQString(aText));
-                pQAG = new QActionGroup(pQMenu);
-            }
-            else
-            {
-                if (pSalMenuItem->mnType == MenuItemType::SEPARATOR)
-                    pQMenu->addSeparator();
-                else
-                {
-                    // leaf menu
-                    QAction* pAction = pQMenu->addAction(toQString(aText));
-                    pSalMenuItem->mpAction = pAction;
-                    
pAction->setShortcut(toQString(nAccelKey.GetName(GetFrame()->GetWindow())));
-
-                    if (itemBits & MenuItemBits::CHECKABLE)
-                    {
-                        pAction->setCheckable(true);
-                        pAction->setChecked(bChecked);
-                    }
-                    else if (itemBits & MenuItemBits::RADIOCHECK)
-                    {
-                        pAction->setCheckable(true);
-                        if (!pQAG)
-                        {
-                            pQAG = new QActionGroup(pQMenu);
-                            pQAG->setExclusive(true);
-                        }
-                        pQAG->addAction(pAction);
-                        pAction->setChecked(bChecked);
-                    }
-
-                    pAction->setEnabled(pSalMenuItem->mbEnabled);
-                    pAction->setVisible(pSalMenuItem->mbVisible);
-
-                    connect(pAction, &QAction::triggered, this,
-                            [pSalMenuItem] { slotMenuTriggered(pSalMenuItem); 
});
-                }
-            }
-        }
+        QMenu* pQMenu = InsertMenuItem(pSalMenuItem, MENU_APPEND);
 
         if (pSalMenuItem->mpSubMenu != nullptr)
         {
@@ -203,17 +280,23 @@ void Qt5Menu::SetItemText(unsigned, SalMenuItem* pItem, 
const OUString& rText)
 
 void Qt5Menu::SetItemImage(unsigned, SalMenuItem* pItem, const Image& rImage)
 {
-    BitmapEx aBmpEx(rImage.GetBitmapEx());
-    Bitmap aBmp(aBmpEx.GetBitmap());
-
-    if (!aBmp || !aBmp.ImplGetSalBitmap())
+    if (!rImage)
         return;
 
-    // simple case, no transparency
     Qt5MenuItem* pSalMenuItem = static_cast<Qt5MenuItem*>(pItem);
     if (pSalMenuItem->mpAction)
-        pSalMenuItem->mpAction->setIcon(QPixmap::fromImage(
-            
*static_cast<Qt5Bitmap*>(aBmp.ImplGetSalBitmap().get())->GetQImage()));
+    {
+        SvMemoryStream aMemStm;
+        vcl::PNGWriter aWriter(rImage.GetBitmapEx());
+        aWriter.Write(aMemStm);
+
+        QImage aImage;
+
+        if (aImage.loadFromData(static_cast<const uchar*>(aMemStm.GetData()), 
aMemStm.TellEnd()))
+        {
+            pSalMenuItem->mpAction->setIcon(QPixmap::fromImage(aImage));
+        }
+    }
 }
 
 void Qt5Menu::SetAccelerator(unsigned, SalMenuItem* pItem, const vcl::KeyCode&,
@@ -251,11 +334,37 @@ void Qt5Menu::slotMenuTriggered(Qt5MenuItem* pQItem)
         Qt5Menu* pSalMenu = pQItem->mpParentMenu;
         Qt5Menu* pTopLevel = pSalMenu->GetTopLevel();
 
-        // it is possible that dispatcher of a menu entry was cleared since
-        // initial activation (happens e.g. when extension comes w/ its own 
menus
-        // and dispatchers) so re-activate the entry before dispatching the 
command
-        pTopLevel->GetMenu()->HandleMenuActivateEvent(pSalMenu->GetMenu());
-        pTopLevel->GetMenu()->HandleMenuCommandEvent(pSalMenu->GetMenu(), 
pQItem->mnId);
+        Menu* pMenu = pSalMenu->GetMenu();
+        auto mnId = pQItem->mnId;
+
+        pTopLevel->GetMenu()->HandleMenuCommandEvent(pMenu, mnId);
+    }
+}
+
+void Qt5Menu::slotMenuAboutToShow(Qt5MenuItem* pQItem)
+{
+    if (pQItem)
+    {
+        Qt5Menu* pSalMenu = pQItem->mpSubMenu;
+        Qt5Menu* pTopLevel = pSalMenu->GetTopLevel();
+
+        Menu* pMenu = pSalMenu->GetMenu();
+
+        // following function may update the menu
+        pTopLevel->GetMenu()->HandleMenuActivateEvent(pMenu);
+    }
+}
+
+void Qt5Menu::slotMenuAboutToHide(Qt5MenuItem* pQItem)
+{
+    if (pQItem)
+    {
+        Qt5Menu* pSalMenu = pQItem->mpSubMenu;
+        Qt5Menu* pTopLevel = pSalMenu->GetTopLevel();
+
+        Menu* pMenu = pSalMenu->GetMenu();
+
+        pTopLevel->GetMenu()->HandleMenuDeActivateEvent(pMenu);
     }
 }
 
@@ -278,4 +387,6 @@ Qt5MenuItem::Qt5MenuItem(const SalItemParams* pItemData)
 {
 }
 
+Qt5MenuItem::~Qt5MenuItem() { delete mpAction; }
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to