[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