[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdevelop/5.3] kdevplatform/sublime: Sublime: Fix crash when changing areas
From:       Amish Naidu <null () kde ! org>
Date:       2018-09-27 17:14:00
Message-ID: E1g5ZrU-0008DO-5S () code ! kde ! org
[Download RAW message or body]

Git commit 7169b3ac931c88783688702ef6013d3d536c68f4 by Amish Naidu.
Committed on 27/09/2018 at 17:12.
Pushed by anaidu into branch '5.3'.

Sublime: Fix crash when changing areas

Summary:
Fixes regression introduced in D15450 by making IdealButtonBarLayout derive from
QBoxLayout instead of QLayout and thus delete most operations to Qt instead
of manually handling them, removing the bugged implementation.

Added minimumSizeHint in IdealToolButton to prevent it from being resized
to zero.

IdealButtonBarLayout is now a child layout for vertical bars as well,
the top level layout is stretched and allows for context menu.

BUG: 399025

Reviewers: #kdevelop, kossebau, rjvbb

Reviewed By: #kdevelop, kossebau, rjvbb

Subscribers: kossebau, rjvbb, kdevelop-devel

Tags: #kdevelop

Differential Revision: https://phabricator.kde.org/D15625

M  +7    -3    kdevplatform/sublime/idealbuttonbarwidget.cpp
M  +24   -247  kdevplatform/sublime/ideallayout.cpp
M  +5    -30   kdevplatform/sublime/ideallayout.h
M  +40   -0    kdevplatform/sublime/idealtoolbutton.cpp
M  +2    -0    kdevplatform/sublime/idealtoolbutton.h

https://commits.kde.org/kdevelop/7169b3ac931c88783688702ef6013d3d536c68f4

diff --git a/kdevplatform/sublime/idealbuttonbarwidget.cpp \
b/kdevplatform/sublime/idealbuttonbarwidget.cpp index d76597411e..24e7899119 100644
--- a/kdevplatform/sublime/idealbuttonbarwidget.cpp
+++ b/kdevplatform/sublime/idealbuttonbarwidget.cpp
@@ -110,12 +110,12 @@ IdealButtonBarWidget::IdealButtonBarWidget(Qt::DockWidgetArea \
area,  setContextMenuPolicy(Qt::CustomContextMenu);
     setToolTip(i18nc("@info:tooltip", "Right click to add new tool views."));
 
+    m_buttonsLayout = new IdealButtonBarLayout(orientation(), this);
     if (area == Qt::BottomDockWidgetArea)
     {
         QBoxLayout *statusLayout = new QBoxLayout(QBoxLayout::LeftToRight, this);
         statusLayout->setMargin(0);
 
-        m_buttonsLayout = new IdealButtonBarLayout(orientation());
         statusLayout->addLayout(m_buttonsLayout);
 
         statusLayout->addStretch(1);
@@ -125,9 +125,13 @@ IdealButtonBarWidget::IdealButtonBarWidget(Qt::DockWidgetArea \
area,  cornerLayout->setMargin(0);
         cornerLayout->setSpacing(0);
         statusLayout->addWidget(m_corner);
+    } else {
+        QBoxLayout *superLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
+        superLayout->setMargin(0);
+
+        superLayout->addLayout(m_buttonsLayout);
+        superLayout->addStretch(1);
     }
-    else
-        m_buttonsLayout = new IdealButtonBarLayout(orientation(), this);
 }
 
 QAction* IdealButtonBarWidget::addWidget(IdealDockWidget *dock,
diff --git a/kdevplatform/sublime/ideallayout.cpp \
b/kdevplatform/sublime/ideallayout.cpp index 8bc4347919..41a328726b 100644
--- a/kdevplatform/sublime/ideallayout.cpp
+++ b/kdevplatform/sublime/ideallayout.cpp
@@ -24,42 +24,37 @@
 
 #include <QStyle>
 #include <QWidget>
+#include <QEvent>
 
 #include <numeric>
 
 using namespace Sublime;
 
-IdealButtonBarLayout::IdealButtonBarLayout(Qt::Orientation orientation, QWidget \
                *parent)
-    : QLayout(parent)
-    , _orientation(orientation)
-    , _height(0)
-
+namespace
 {
-    setContentsMargins(0, 0, 0, 0);
-    invalidate();
-}
 
-void IdealButtonBarLayout::invalidate()
-{
-    m_minSizeDirty = true;
-    m_sizeHintDirty = true;
-    m_layoutDirty = true;
-    QLayout::invalidate();
-}
+    QBoxLayout::Direction toDirection(Qt::Orientation orientation)
+    {
+        return orientation == Qt::Horizontal ? QBoxLayout::LeftToRight : \
QBoxLayout::TopToBottom; +    }
 
-IdealButtonBarLayout::~IdealButtonBarLayout()
-{
-    qDeleteAll(_items);
 }
 
-void IdealButtonBarLayout::setHeight(int height)
+IdealButtonBarLayout::IdealButtonBarLayout(Qt::Orientation orientation, QWidget* \
styleParent) +    : QBoxLayout(toDirection(orientation)) // creating a child layout, \
styleParent is only saved for style +    , m_styleParentWidget(styleParent)
+    , _orientation(orientation)
 {
-    Q_ASSERT(orientation() == Qt::Vertical);
-    _height = height;
+    if (m_styleParentWidget) {
+        m_styleParentWidget->installEventFilter(this);
+    }
 
-    (void) invalidate();
+    setContentsMargins(0, 0, 0, 0);
+    setSpacing(buttonSpacing());
 }
 
+IdealButtonBarLayout::~IdealButtonBarLayout() = default;
+
 Qt::Orientation IdealButtonBarLayout::orientation() const
 {
     return _orientation;
@@ -70,237 +65,19 @@ Qt::Orientations IdealButtonBarLayout::expandingDirections() \
const  return orientation();
 }
 
-QSize IdealButtonBarLayout::minimumSize() const
-{
-    // The code below appears to be completely wrong --
-    // it will return the maximum size of a single button, not any
-    // estimate as to how much space is necessary to draw all buttons
-    // in a minimally acceptable way.
-    if (m_minSizeDirty) {
-        if (orientation() == Qt::Vertical) {
-            const int width = doVerticalLayout(QRect(0, 0, 0, _height), false);
-            return QSize(width, 0);
-        }
-
-        m_min = QSize(0, 0);
-        for (QLayoutItem* item : _items) {
-            m_min = m_min.expandedTo(item->minimumSize());
-        }
-
-        m_minSizeDirty = false;
-    }
-    return m_min;
-}
-
-QSize IdealButtonBarLayout::sizeHint() const
-{
-    if (m_sizeHintDirty) {
-        const int buttonSpacing = this->buttonSpacing();
-
-        int orientationSize = 0;
-        int crossSize = 0;
-
-        bool first = true;
-        for (QLayoutItem *item : _items) {
-            QSize hint = item->sizeHint();
-            int orientationSizeHere;
-            int crossSizeHere;
-            if (orientation() == Qt::Vertical)
-            {
-                orientationSizeHere = hint.height();
-                crossSizeHere = hint.width();
-            }
-            else
-            {
-                orientationSizeHere = hint.width();
-                crossSizeHere = hint.height();
-            }
-
-            if (first)
-            {
-                crossSize = crossSizeHere;
-            }
-            else
-            {
-                orientationSize += buttonSpacing;
-            }
-            orientationSize += orientationSizeHere;
-            first = false;
-        }
-
-        if (orientation() == Qt::Vertical)
-            m_hint = QSize(crossSize, orientationSize);
-        else
-            m_hint = QSize(orientationSize, crossSize);
-
-        if (!_items.empty())
-        {
-            /* If we have no items, just use (0, 0) as hint, don't
-               append any margins.  */
-            int l, t, r, b;
-            getContentsMargins(&l, &t, &r, &b);
-            m_hint += QSize(l+r, t+b);
-        }
-
-        m_sizeHintDirty = false;
-    }
-    return m_hint;
-}
-
-void IdealButtonBarLayout::setGeometry(const QRect &rect)
-{
-    if (m_layoutDirty || rect != geometry()) {
-        if (orientation() == Qt::Vertical)
-            doVerticalLayout(rect);
-        else
-            doHorizontalLayout(rect);
-    }
-}
-
-void IdealButtonBarLayout::addItem(QLayoutItem *item)
-{
-    _items.append(item);
-    invalidate();
-}
-
-QLayoutItem* IdealButtonBarLayout::itemAt(int index) const
-{
-    return _items.value(index, nullptr);
-}
-
-QLayoutItem* IdealButtonBarLayout::takeAt(int index)
-{
-    if (index >= 0 && index < _items.count())
-        return _items.takeAt(index);
-    invalidate();
-    return nullptr;
-}
-
-int IdealButtonBarLayout::count() const
-{
-    return _items.count();
-}
-
 int IdealButtonBarLayout::buttonSpacing() const
 {
-    auto pw = parentWidget();
-    return pw ? pw->style()->pixelMetric(QStyle::PM_ToolBarItemSpacing) : 0;
-}
-
-
-int IdealButtonBarLayout::doVerticalLayout(const QRect &rect, bool updateGeometry) \
                const
-{
-    const int buttonSpacing = this->buttonSpacing();
-
-    int l, t, r, b;
-    getContentsMargins(&l, &t, &r, &b);
-    int x = rect.x() + l;
-    int y = rect.y() + t;
-    int currentLineWidth = 0;
-
-    if (_items.empty()) {
-        return x + currentLineWidth + r;
-    }
-
-    const bool shrink = rect.height() < sizeHint().height();
-
-    const int maximumHeight = rect.height() / _items.size();
-    int shrinkedHeight = -1;
-
-    if (shrink) {
-        int smallItemCount = 0;
-        const int surplus = std::accumulate(_items.begin(), _items.end(), 0, \
                [maximumHeight, &smallItemCount](int acc, QLayoutItem* item) {
-            const int itemHeight = item->sizeHint().height();
-            if (itemHeight <= maximumHeight) {
-                acc += maximumHeight - itemHeight;
-                ++smallItemCount;
-            }
-            return acc;
-        });
-
-        Q_ASSERT(_items.size() != smallItemCount); // should be true since \
                rect.width != sizeHint.width
-        // evenly distribute surplus height over large items
-        shrinkedHeight = maximumHeight + surplus / (_items.size() - smallItemCount);
+    if (!m_styleParentWidget) {
+        return 0;
     }
-
-    for (QLayoutItem* item : _items) {
-        const QSize itemSizeHint = item->sizeHint();
-        const int itemWidth  = itemSizeHint.width();
-        int itemHeight = itemSizeHint.height();
-
-        if (shrink && itemSizeHint.height() > maximumHeight) {
-            itemHeight = shrinkedHeight;
-        }
-
-        if (updateGeometry) {
-            item->setGeometry(QRect(x, y, itemWidth, itemHeight));
-        }
-
-        currentLineWidth = qMax(currentLineWidth, itemWidth);
-
-        y += itemHeight + buttonSpacing;
-    }
-
-    m_layoutDirty = updateGeometry;
-
-    return x + currentLineWidth + r;
+    return m_styleParentWidget->style()->pixelMetric(QStyle::PM_ToolBarItemSpacing);
 }
 
-int IdealButtonBarLayout::doHorizontalLayout(const QRect &rect, bool updateGeometry) \
const +bool IdealButtonBarLayout::eventFilter(QObject* watched, QEvent* event)
 {
-    const int buttonSpacing = this->buttonSpacing();
-
-    int l, t, r, b;
-    getContentsMargins(&l, &t, &r, &b);
-    int x = rect.x() + l;
-    int y = rect.y() + t;
-    int currentLineHeight = 0;
-
-    if (_items.empty()) {
-        return y + currentLineHeight + b;
+    if (event->type() == QEvent::StyleChange) {
+        setSpacing(buttonSpacing());
     }
 
-    const bool shrink = rect.width() < sizeHint().width();
-
-    const int maximumWidth = rect.width() / _items.size();
-    int shrinkedWidth = -1;
-
-    if (shrink) {
-        int smallItemCount = 0;
-        const int surplus = std::accumulate(_items.begin(), _items.end(), 0, \
                [maximumWidth, &smallItemCount](int acc, QLayoutItem* item) {
-            const int itemWidth = item->sizeHint().width();
-            if (itemWidth <= maximumWidth) {
-                acc += maximumWidth - itemWidth;
-                ++smallItemCount;
-            }
-            return acc;
-        });
-
-        Q_ASSERT(_items.size() != smallItemCount); // should be true since \
                rect.width != sizeHint.width
-        // evenly distribute surplus width on the large items
-        shrinkedWidth = maximumWidth + surplus / (_items.size() - smallItemCount);
-    }
-
-    for (QLayoutItem* item : _items) {
-        const QSize itemSizeHint = item->sizeHint();
-        int itemWidth  = itemSizeHint.width();
-        const int itemHeight = itemSizeHint.height();
-
-        if (shrink && itemSizeHint.width() > maximumWidth) {
-            itemWidth = shrinkedWidth;
-        }
-
-        if (updateGeometry) {
-            item->setGeometry(QRect(x, y, itemWidth, itemHeight));
-        }
-
-        currentLineHeight = qMax(currentLineHeight, itemHeight);
-
-        x += itemWidth + buttonSpacing;
-    }
-
-    m_layoutDirty = updateGeometry;
-
-    return y + currentLineHeight + b;
+    return QBoxLayout::eventFilter(watched, event);
 }
-
diff --git a/kdevplatform/sublime/ideallayout.h b/kdevplatform/sublime/ideallayout.h
index faf2fac077..2983dd6336 100644
--- a/kdevplatform/sublime/ideallayout.h
+++ b/kdevplatform/sublime/ideallayout.h
@@ -22,59 +22,34 @@
 #ifndef KDEVPLATFORM_SUBLIME_IDEALLAYOUT_H
 #define KDEVPLATFORM_SUBLIME_IDEALLAYOUT_H
 
-#include <QLayout>
+#include <QBoxLayout>
 
 #include "sublimedefs.h"
 
 namespace Sublime {
 
-class IdealButtonBarLayout: public QLayout
+class IdealButtonBarLayout: public QBoxLayout
 {
     Q_OBJECT
 
 public:
-    explicit IdealButtonBarLayout(Qt::Orientation orientation, QWidget *parent = \
nullptr); +    IdealButtonBarLayout(Qt::Orientation orientation, QWidget* \
styleParent);  
     ~IdealButtonBarLayout() override;
 
-    void setHeight(int height);
-
     inline Qt::Orientation orientation() const;
 
     Qt::Orientations expandingDirections() const override;
 
-    QSize minimumSize() const override;
-
-    QSize sizeHint() const override;
-
-    void setGeometry(const QRect &rect) override;
-
-    void addItem(QLayoutItem *item) override;
-
-    QLayoutItem* itemAt(int index) const override;
-
-    QLayoutItem* takeAt(int index) override;
-
-    int count() const override;
-
-    void invalidate() override;
-
 protected:
-    int doVerticalLayout(const QRect &rect, bool updateGeometry = true) const;
 
-    int doHorizontalLayout(const QRect &rect, bool updateGeometry = true) const;
+    bool eventFilter(QObject* watched, QEvent* event) override;
 
     int buttonSpacing() const;
 
 private:
-    QList<QLayoutItem *> _items;
+    QWidget* const m_styleParentWidget;
     const Qt::Orientation _orientation;
-    int _height;
-    mutable bool m_minSizeDirty : 1;
-    mutable bool m_sizeHintDirty : 1;
-    mutable bool m_layoutDirty : 1;
-    mutable QSize m_min;
-    mutable QSize m_hint;
 };
 
 }
diff --git a/kdevplatform/sublime/idealtoolbutton.cpp \
b/kdevplatform/sublime/idealtoolbutton.cpp index 01dbfefe24..564042b463 100644
--- a/kdevplatform/sublime/idealtoolbutton.cpp
+++ b/kdevplatform/sublime/idealtoolbutton.cpp
@@ -2,6 +2,7 @@
   Copyright 2007 Roberto Raggi <roberto@kdevelop.org>
   Copyright 2007 Hamish Rodda <rodda@kde.org>
   Copyright 2011 Alexander Dymo <adymo@kdevelop.org>
+  Copyright 2018 Amish Naidu <amhndu@gmail.com>
 
   Permission to use, copy, modify, distribute, and sell this software and its
   documentation for any purpose is hereby granted without fee, provided that
@@ -24,6 +25,7 @@
 #include <KAcceleratorManager>
 #include <QStyleOption>
 #include <QStylePainter>
+#include <QApplication>
 
 IdealToolButton::IdealToolButton(Qt::DockWidgetArea area, QWidget *parent)
     : QToolButton(parent), _area(area)
@@ -35,6 +37,14 @@ IdealToolButton::IdealToolButton(Qt::DockWidgetArea area, QWidget \
*parent)  setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
 
     setContextMenuPolicy(Qt::CustomContextMenu);
+
+    QSizePolicy sizePolicy = this->sizePolicy();
+    if (orientation() == Qt::Horizontal) {
+        sizePolicy.setHorizontalPolicy(QSizePolicy::Maximum);
+    } else {
+        sizePolicy.setVerticalPolicy(QSizePolicy::Maximum);
+    }
+    setSizePolicy(sizePolicy);
 }
 
 Qt::Orientation IdealToolButton::orientation() const
@@ -86,6 +96,36 @@ QSize IdealToolButton::sizeHint() const
     }
 }
 
+QSize IdealToolButton::minimumSizeHint() const
+{
+    ensurePolished();
+
+    QStyleOptionToolButton opt;
+    initStyleOption(&opt);
+
+    QSize minimumSize;
+    // if style has icons, minimumSize is the size of the icon
+    if (toolButtonStyle() != Qt::ToolButtonTextOnly && !opt.icon.isNull()) {
+        minimumSize = opt.iconSize;
+        if (_area == Qt::LeftDockWidgetArea || _area == Qt::RightDockWidgetArea) {
+            minimumSize.transpose();
+        }
+    } else {
+        // if no icon, set an arbitrary minimum size
+        QFontMetrics fm = fontMetrics();
+        minimumSize = fm.size(Qt::TextShowMnemonic, opt.text.left(4));
+    }
+
+    minimumSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, \
minimumSize, this). +                  expandedTo(QApplication::globalStrut());
+
+    if (_area == Qt::TopDockWidgetArea || _area == Qt::BottomDockWidgetArea) {
+        return minimumSize;
+    }
+    return minimumSize.transposed();
+}
+
+
 void IdealToolButton::paintEvent(QPaintEvent *event)
 {
     Q_UNUSED(event);
diff --git a/kdevplatform/sublime/idealtoolbutton.h \
b/kdevplatform/sublime/idealtoolbutton.h index 3497e39018..7449172d92 100644
--- a/kdevplatform/sublime/idealtoolbutton.h
+++ b/kdevplatform/sublime/idealtoolbutton.h
@@ -36,6 +36,8 @@ public:
 
     QSize sizeHint() const override;
 
+    QSize minimumSizeHint() const override;
+
 protected:
     void paintEvent(QPaintEvent *event) override;
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic