diff --git a/autotests/kcolorbuttontest.cpp b/autotests/kcolorbuttontest.cpp index d87fb09..becfe48 100644 --- a/autotests/kcolorbuttontest.cpp +++ b/autotests/kcolorbuttontest.cpp @@ -1,40 +1,38 @@ /* Copyright 2013 Albert Astals Cid This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcolorbuttontest.h" #include #include #include -#include -#include QTEST_MAIN(KColorButtonTest) void KColorButtonTest::testOpenDialog() { KColorButton colorButton(Qt::red); colorButton.show(); QVERIFY(QTest::qWaitForWindowExposed(&colorButton)); QTest::mouseClick(&colorButton, Qt::LeftButton); QColorDialog *dialog = colorButton.findChild(); QVERIFY(dialog != nullptr); QVERIFY(QTest::qWaitForWindowExposed(dialog)); QCOMPARE(dialog->currentColor(), QColor(Qt::red)); } diff --git a/autotests/kcolorbuttontest.h b/autotests/kcolorbuttontest.h index c4eb727..98e6440 100644 --- a/autotests/kcolorbuttontest.h +++ b/autotests/kcolorbuttontest.h @@ -1,34 +1,33 @@ /* Copyright 2013 Albert Astals Cid This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KCOLORBUTTONTEST_H #define KCOLORBUTTONTEST_H #include -#include class KColorButtonTest : public QObject { Q_OBJECT private Q_SLOTS: void testOpenDialog(); }; #endif diff --git a/autotests/kcolumnresizertest.cpp b/autotests/kcolumnresizertest.cpp index 0a1c4f4..6017859 100644 --- a/autotests/kcolumnresizertest.cpp +++ b/autotests/kcolumnresizertest.cpp @@ -1,90 +1,87 @@ /* This file is part of the KDE frameworks * * Copyright (c) 2014 Aurélien Gâteau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include #include -#include -#include -#include #include "ui_kcolumnresizertest-forms.h" #include "ui_kcolumnresizertest-grids.h" #include "ui_kcolumnresizertest-grid-and-form.h" #include QTEST_MAIN(KColumnResizerTest) void KColumnResizerTest::test_data() { QTest::addColumn("parent"); QWidget *forms = new QWidget; Ui::KColumnResizerTestForms().setupUi(forms); QTest::newRow("forms") << forms; QWidget *grids = new QWidget; Ui::KColumnResizerTestGrids().setupUi(grids); QTest::newRow("grids") << grids; QWidget *gridAndForm = new QWidget; Ui::KColumnResizerTestGridAndForms().setupUi(gridAndForm); QTest::newRow("grid-and-form") << gridAndForm; } void KColumnResizerTest::test() { // This test checks the x coordinate of the widgets from the column // immediately after the resized column, rather than checking the width of // the resized column itself because checking the width of the column cannot // be done the same way for all layout types. QFETCH(QWidget *, parent); QVERIFY(parent); auto layout1 = parent->findChild(QStringLiteral("layout1")); auto layout2 = parent->findChild(QStringLiteral("layout2")); auto widget1 = parent->findChild(QStringLiteral("widget1")); auto widget2 = parent->findChild(QStringLiteral("widget2")); QVERIFY(layout1); QVERIFY(layout2); QVERIFY(widget1); QVERIFY(widget2); // Show the widget so that geometries are updated parent->show(); int widget1x = widget1->x(); int widget2x = widget2->x(); QVERIFY(widget1x < widget2x); auto resizer = new KColumnResizer(parent); resizer->addWidgetsFromLayout(layout1); resizer->addWidgetsFromLayout(layout2); // Wait for resizer to do the work QCoreApplication::processEvents(); // Now wait for the layout change to propagate QCoreApplication::processEvents(); QCOMPARE(widget1->x(), widget2x); QCOMPARE(widget2->x(), widget2x); delete parent; } diff --git a/autotests/kpassworddialogautotest.cpp b/autotests/kpassworddialogautotest.cpp index aec8e57..dc285c9 100644 --- a/autotests/kpassworddialogautotest.cpp +++ b/autotests/kpassworddialogautotest.cpp @@ -1,51 +1,50 @@ /* Copyright 2017 Elvis Angelaccio This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kpassworddialogautotest.h" #include -#include #include #include #include QTEST_MAIN(KPasswordDialogAutotest) void KPasswordDialogAutotest::shouldNotHideVisibilityActionInPlaintextMode() { KPasswordDialog dialog; auto linePassword = dialog.findChild(QStringLiteral("passEdit")); QVERIFY(linePassword); auto lineEdit = linePassword->lineEdit(); QVERIFY(lineEdit); auto visibilityAction = lineEdit->findChild(QStringLiteral("visibilityAction")); QVERIFY(visibilityAction && !visibilityAction->isVisible()); linePassword->lineEdit()->setText(QStringLiteral("1234")); QVERIFY(visibilityAction->isVisible()); visibilityAction->trigger(); linePassword->clear(); QVERIFY(visibilityAction->isVisible()); } diff --git a/autotests/ktooltipwidgettest.cpp b/autotests/ktooltipwidgettest.cpp index 1511f17..f75ea21 100644 --- a/autotests/ktooltipwidgettest.cpp +++ b/autotests/ktooltipwidgettest.cpp @@ -1,239 +1,237 @@ /* * Copyright (c) 2017 Elvis Angelaccio * Copyright (c) 2018 Michael Heidelbach * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "ktooltipwidgettest.h" #include -#include -#include -#include #include #include #include #include #include +#include #include void KToolTipWidgetTest::initTestCase() { m_screenGeometry = QGuiApplication::primaryScreen()->geometry(); } void KToolTipWidgetTest::showTooltipShouldShowContent() { KToolTipWidget tooltip; QLabel label; tooltip.showAt(QPoint(10, 10), &label, nullptr); QVERIFY(tooltip.isVisible()); QVERIFY(label.isVisible()); } void KToolTipWidgetTest::hideLaterShouldHideAfterDelay() { KToolTipWidget tooltip; QLabel label; tooltip.showAt(QPoint(10, 10), &label, nullptr); QVERIFY(tooltip.isVisible()); QVERIFY(label.isVisible()); tooltip.hideLater(); QVERIFY(tooltip.isVisible()); QVERIFY(label.isVisible()); QSignalSpy spy(&tooltip, &KToolTipWidget::hidden); connect(&tooltip, &KToolTipWidget::hidden, this, [&]() { QVERIFY(tooltip.isHidden()); QVERIFY(!label.isVisible()); }); QEventLoop eventLoop; connect(&tooltip, &KToolTipWidget::hidden, &eventLoop, &QEventLoop::quit); QCOMPARE(eventLoop.exec(), 0); QCOMPARE(spy.count(), 1); } void KToolTipWidgetTest::setZeroDelayShouldHideImmediately() { KToolTipWidget tooltip; QLabel label; tooltip.setHideDelay(0); tooltip.showAt(QPoint(10, 10), &label, nullptr); QVERIFY(tooltip.isVisible()); QVERIFY(label.isVisible()); tooltip.hideLater(); QVERIFY(tooltip.isHidden()); QVERIFY(!label.isVisible()); } void KToolTipWidgetTest::shouldHideImmediatelyIfContentDestroyed() { KToolTipWidget tooltip; auto lineEdit = new QLineEdit(); tooltip.showAt(QPoint(10, 10), lineEdit, nullptr); QVERIFY(tooltip.isVisible()); delete lineEdit; QVERIFY(tooltip.isHidden()); } void KToolTipWidgetTest::shouldNotTakeOwnershipOfContent() { auto parent = new QWidget(); auto label = new QLabel(parent); auto tooltip = new KToolTipWidget(); tooltip->showAt(QPoint(10, 10), label, nullptr); QCOMPARE(label->parent(), tooltip); QVERIFY(label->isVisible()); QSignalSpy spy(label, &QWidget::destroyed); delete tooltip; QVERIFY(!label->isVisible()); QCOMPARE(label->parent(), parent); QCOMPARE(spy.count(), 0); delete parent; QCOMPARE(spy.count(), 1); } void KToolTipWidgetTest::shouldNotObscureTarget_data() { qDebug() << "Style used" << QApplication::style()->objectName(); QTest::addColumn("position"); QTest::addColumn("content"); const QMap positions{ {QStringLiteral("topleft"), QPoint(m_offset, m_offset)}, {QStringLiteral("topright"), QPoint(-m_offset, m_offset)}, {QStringLiteral("bottomright"), QPoint(-m_offset, -m_offset)}, {QStringLiteral("bottomleft"), QPoint(m_offset, -m_offset)}, {QStringLiteral("centered"), QPoint(m_screenGeometry.width() / 2, m_screenGeometry.height() / 2)} }; QMapIterator i(positions); while (i.hasNext()) { i.next(); QTest::newRow(qPrintable(QStringLiteral("small/%1").arg(i.key())) ) << i.value() << QStringLiteral("dummy text"); QTest::newRow(qPrintable(QStringLiteral("multiline/%1").arg(i.key()))) << i.value() << QStringLiteral("dummy text\nLine 1\nLine 2\nLine 3"); QTest::newRow(qPrintable(QStringLiteral("one long line/%1").arg(i.key()))) << i.value() << QStringLiteral( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec felis sed elit auctor lobortis non a urna. Quisque non posuere mauris. Suspendisse potenti. In diam leo, lobortis at placerat nec, sagittis at tortor. Pellentesque scelerisque enim vel elementum scelerisque. Integer eget lectus vitae lorem pulvinar hendrerit. Suspendisse auctor sapien vel semper porta. Vestibulum fringilla aliquet tincidunt. Maecenas mollis mauris et erat viverra mollis. Proin suscipit felis nisi, a dapibus est hendrerit euismod. Suspendisse quis faucibus quam. Fusce eu cursus magna, et egestas purus. Duis enim sapien, feugiat id facilisis non, rhoncus ut lectus. Aliquam at nisi vel ligula interdum ultricies. Donec condimentum ante quam, eu congue lectus pulvinar in. Cras interdum, neque quis fermentum consequat, lectus tellus eleifend turpis." ); if (m_screenGeometry.width() >= 1600 && m_screenGeometry.height() >= 900) { QTest::newRow(qPrintable(QStringLiteral("super large/%1").arg(i.key()))) << i.value() << QStringLiteral( "dummy 0 text\nLine 1\nLine 2\nLine 3" "dummy 1 text\nLine 1\nLine 2\nLine 3" "dummy 2 text\nLine 1\nLine 2\nLine 3" "dummy 3 text\nLine 1\nLine 2\nLine 3" "dummy 4 text\nLine 1\nLine 2\nLine 3" "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec felis sed elit auctor lobortis non a urna. Quisque non posuere mauris. Suspendisse potenti. In diam leo, lobortis at placerat nec, sagittis at tortor. Pellentesque scelerisque enim vel elementum scelerisque. Integer eget lectus vitae lorem pulvinar hendrerit. Suspendisse auctor sapien vel semper porta. Vestibulum fringilla aliquet tincidunt. Maecenas mollis mauris et erat viverra mollis. Proin suscipit felis nisi, a dapibus est hendrerit euismod. Suspendisse quis faucibus quam. Fusce eu cursus magna, et egestas purus. Duis enim sapien, feugiat id facilisis non, rhoncus ut lectus. Aliquam at nisi vel ligula interdum ultricies. Donec condimentum ante quam, eu congue lectus pulvinar in. Cras interdum, neque quis fermentum consequat, lectus tellus eleifend turpis." ); } } } void KToolTipWidgetTest::shouldNotObscureTarget() { QFETCH(QPoint, position); QFETCH(QString, content); QWidget* containerWidget = new QWidget(); const int margin = containerWidget->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth); QLabel* targetWidget = new QLabel(QStringLiteral("dummy file")); QLayout* layout = new QHBoxLayout(containerWidget); layout->addWidget(targetWidget); containerWidget->adjustSize(); containerWidget->move( position.x() >= 0 ? position.x() : m_screenGeometry.right() + position.x() - containerWidget->width(), position.y() >= 0 ? position.y() : m_screenGeometry.bottom() + position.y() - containerWidget->height() ); containerWidget->show(); QVERIFY(QTest::qWaitForWindowActive(containerWidget)); QVERIFY(targetWidget->isVisible()); QRect targetRect = QRect(targetWidget->frameGeometry()); targetRect.moveTo(targetWidget->mapToGlobal(QPoint(0, 0))); QLabel* contentWidget = new QLabel(content); QVERIFY2(containerWidget->windowHandle(), "Container's window handle is invalid"); KToolTipWidget tooltipWidget; tooltipWidget.showBelow(targetRect, contentWidget, containerWidget->windowHandle()); QVERIFY(QTest::qWaitForWindowActive(&tooltipWidget)); const QRect tooltipRect = tooltipWidget.frameGeometry(); qDebug() << QStringLiteral("tooltip: %1x%2 x=%3, y=%4") .arg(tooltipRect.width()) .arg(tooltipRect.height()) .arg(tooltipRect.left()) .arg(tooltipRect.top()); qDebug() << QStringLiteral("target: %1x%2 x=%3, y=%4") .arg(targetRect.width()) .arg(targetRect.height()) .arg(targetRect.left()) .arg(targetRect.top()); QVERIFY2(!tooltipRect.intersects(targetRect), "Target obscured"); QCOMPARE(tooltipRect.intersected(m_screenGeometry), tooltipRect); // Check margins if (tooltipRect.bottom() < targetRect.top()) { QCOMPARE(margin, targetRect.top() - tooltipRect.bottom()); } else if (tooltipRect.top() > targetRect.bottom()) { QCOMPARE(margin, tooltipRect.top() - targetRect.bottom()); } else if (tooltipRect.right() < targetRect.left()) { QCOMPARE(margin, targetRect.left() - tooltipRect.right()); } else if (tooltipRect.left() > targetRect.right() ) { QCOMPARE(margin, tooltipRect.left() - targetRect.right()); } tooltipWidget.hide(); QVERIFY(tooltipWidget.isHidden()); delete contentWidget; delete containerWidget; } QTEST_MAIN(KToolTipWidgetTest) diff --git a/src/common_helpers.cpp b/src/common_helpers.cpp index ca14910..af2e108 100644 --- a/src/common_helpers.cpp +++ b/src/common_helpers.cpp @@ -1,106 +1,105 @@ /* This file is part of the KDE libraries Copyright (C) 2008 Chusslove Illich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#include // If pos points to alphanumeric X in "...(X)...", which is preceded or // followed only by non-alphanumerics, then "(X)" gets removed. static QString removeReducedCJKAccMark(const QString &label, int pos) { if (pos > 0 && pos + 1 < label.length() && label[pos - 1] == QLatin1Char('(') && label[pos + 1] == QLatin1Char(')') && label[pos].isLetterOrNumber()) { // Check if at start or end, ignoring non-alphanumerics. int len = label.length(); int p1 = pos - 2; while (p1 >= 0 && !label[p1].isLetterOrNumber()) { --p1; } ++p1; int p2 = pos + 2; while (p2 < len && !label[p2].isLetterOrNumber()) { ++p2; } --p2; if (p1 == 0) { return label.leftRef(pos - 1) + label.midRef(p2 + 1); } else if (p2 + 1 == len) { return label.leftRef(p1) + label.midRef(pos + 2); } } return label; } QString removeAcceleratorMarker(const QString &label_) { QString label = label_; int p = 0; bool accmarkRemoved = false; while (true) { p = label.indexOf(QLatin1Char('&'), p); if (p < 0 || p + 1 == label.length()) { break; } if (label[p + 1].isLetterOrNumber()) { // Valid accelerator. label = QString(label.leftRef(p) + label.midRef(p + 1)); // May have been an accelerator in CJK-style "(&X)" // at the start or end of text. label = removeReducedCJKAccMark(label, p); accmarkRemoved = true; } else if (label[p + 1] == QLatin1Char('&')) { // Escaped accelerator marker. label = QString(label.leftRef(p) + label.midRef(p + 1)); } ++p; } // If no marker was removed, and there are CJK characters in the label, // also try to remove reduced CJK marker -- something may have removed // ampersand beforehand. if (!accmarkRemoved) { bool hasCJK = false; foreach (const QChar c, label) { if (c.unicode() >= 0x2e00) { // rough, but should be sufficient hasCJK = true; break; } } if (hasCJK) { p = 0; while (true) { p = label.indexOf(QLatin1Char('('), p); if (p < 0) { break; } label = removeReducedCJKAccMark(label, p + 1); ++p; } } } return label; } diff --git a/src/kacceleratormanager.cpp b/src/kacceleratormanager.cpp index 478218f..a5e2325 100644 --- a/src/kacceleratormanager.cpp +++ b/src/kacceleratormanager.cpp @@ -1,857 +1,854 @@ /* This file is part of the KDE project Copyright (C) 2002 Matthias Hölzer-Klüpfel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kacceleratormanager.h" #include "kacceleratormanager_p.h" #include #include #include #include #include #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include -#include -#include +#include #include "loggingcategory.h" #include "common_helpers_p.h" /********************************************************************* class Item - helper class containing widget information This class stores information about the widgets the need accelerators, as well as about their relationship. *********************************************************************/ bool KAcceleratorManagerPrivate::programmers_mode = false; QString KAcceleratorManagerPrivate::changed_string; QString KAcceleratorManagerPrivate::added_string; QString KAcceleratorManagerPrivate::removed_string; QMap KAcceleratorManagerPrivate::ignored_widgets; QStringList KAcceleratorManagerPrivate::standardNames; void KAcceleratorManagerPrivate::addStandardActionNames(const QStringList &list) { standardNames.append(list); } bool KAcceleratorManagerPrivate::standardName(const QString &str) { return standardNames.contains(str); } KAcceleratorManagerPrivate::Item::~Item() { if (m_children) { while (!m_children->isEmpty()) { delete m_children->takeFirst(); } delete m_children; } } void KAcceleratorManagerPrivate::Item::addChild(Item *item) { if (!m_children) { m_children = new ItemList; } m_children->append(item); } void KAcceleratorManagerPrivate::manage(QWidget *widget) { if (!widget) { qCDebug(KWidgetsAddonsLog) << "null pointer given to manage"; return; } if (KAcceleratorManagerPrivate::ignored_widgets.contains(widget)) { return; } if (qobject_cast(widget)) { // create a popup accel manager that can deal with dynamic menus KPopupAccelManager::manage(static_cast(widget)); return; } Item *root = new Item; manageWidget(widget, root); QString used; calculateAccelerators(root, used); delete root; } void KAcceleratorManagerPrivate::calculateAccelerators(Item *item, QString &used) { if (!item->m_children) { return; } // collect the contents KAccelStringList contents; Q_FOREACH (Item *it, *item->m_children) { contents << it->m_content; } // find the right accelerators KAccelManagerAlgorithm::findAccelerators(contents, used); // write them back into the widgets int cnt = -1; Q_FOREACH (Item *it, *item->m_children) { cnt++; QDockWidget *dock = qobject_cast(it->m_widget); if (dock) { if (checkChange(contents[cnt])) { dock->setWindowTitle(contents[cnt].accelerated()); } continue; } QTabBar *tabBar = qobject_cast(it->m_widget); if (tabBar) { if (checkChange(contents[cnt])) { tabBar->setTabText(it->m_index, contents[cnt].accelerated()); } continue; } QMenuBar *menuBar = qobject_cast(it->m_widget); if (menuBar) { if (it->m_index >= 0) { QAction *maction = menuBar->actions()[it->m_index]; if (maction) { checkChange(contents[cnt]); maction->setText(contents[cnt].accelerated()); } continue; } } // we possibly reserved an accel, but we won't set it as it looks silly QGroupBox *groupBox = qobject_cast(it->m_widget); if (groupBox && !groupBox->isCheckable()) { continue; } int tprop = it->m_widget->metaObject()->indexOfProperty("text"); if (tprop != -1) { if (checkChange(contents[cnt])) { it->m_widget->setProperty("text", contents[cnt].accelerated()); } } else { tprop = it->m_widget->metaObject()->indexOfProperty("title"); if (tprop != -1 && checkChange(contents[cnt])) { it->m_widget->setProperty("title", contents[cnt].accelerated()); } } } // calculate the accelerators for the children Q_FOREACH (Item *it, *item->m_children) { if (it->m_widget && it->m_widget->isVisibleTo(item->m_widget)) { calculateAccelerators(it, used); } } } void KAcceleratorManagerPrivate::traverseChildren(QWidget *widget, Item *item) { QList childList = widget->findChildren(); Q_FOREACH (QWidget *w, childList) { // Ignore unless we have the direct parent if (qobject_cast(w->parent()) != widget) { continue; } if (!w->isVisibleTo(widget) || (w->isTopLevel() && qobject_cast(w) == nullptr)) { continue; } if (KAcceleratorManagerPrivate::ignored_widgets.contains(w)) { continue; } manageWidget(w, item); } } void KAcceleratorManagerPrivate::manageWidget(QWidget *w, Item *item) { // first treat the special cases QTabBar *tabBar = qobject_cast(w); if (tabBar) { manageTabBar(tabBar, item); return; } QStackedWidget *wds = qobject_cast(w); if (wds) { QWidgetStackAccelManager::manage(wds); // return; } QDockWidget *dock = qobject_cast(w); if (dock) { //QWidgetStackAccelManager::manage( wds ); manageDockWidget(dock, item); } QMenu *popupMenu = qobject_cast(w); if (popupMenu) { // create a popup accel manager that can deal with dynamic menus KPopupAccelManager::manage(popupMenu); return; } QStackedWidget *wdst = qobject_cast(w); if (wdst) { QWidgetStackAccelManager::manage(wdst); // return; } QMenuBar *menuBar = qobject_cast(w); if (menuBar) { manageMenuBar(menuBar, item); return; } if (qobject_cast(w) || qobject_cast(w) || w->inherits("Q3TextEdit") || qobject_cast(w) || qobject_cast(w) || w->inherits("KMultiTabBar") || w->inherits("qdesigner_internal::TextPropertyEditor")) { return; } if (w->inherits("KUrlRequester")) { traverseChildren(w, item); return; } // now treat 'ordinary' widgets QLabel *label = qobject_cast(w); if (label) { if (!label->buddy()) { return; } else { if (label->textFormat() == Qt::RichText || (label->textFormat() == Qt::AutoText && Qt::mightBeRichText(label->text()))) { return; } } } if (w->focusPolicy() != Qt::NoFocus || label || qobject_cast(w) || qobject_cast(w)) { QString content; QVariant variant; int tprop = w->metaObject()->indexOfProperty("text"); if (tprop != -1) { QMetaProperty p = w->metaObject()->property(tprop); if (p.isValid() && p.isWritable()) { variant = p.read(w); } else { tprop = -1; } } if (tprop == -1) { tprop = w->metaObject()->indexOfProperty("title"); if (tprop != -1) { QMetaProperty p = w->metaObject()->property(tprop); if (p.isValid() && p.isWritable()) { variant = p.read(w); } } } if (variant.isValid()) { content = variant.toString(); } if (!content.isEmpty()) { Item *i = new Item; i->m_widget = w; // put some more weight on the usual action elements int weight = KAccelManagerAlgorithm::DEFAULT_WEIGHT; if (qobject_cast(w) || qobject_cast(w) || qobject_cast(w) || qobject_cast(w)) { weight = KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT; } // don't put weight on non-checkable group boxes, // as usually the contents are more important QGroupBox *groupBox = qobject_cast(w); if (groupBox) { if (groupBox->isCheckable()) { weight = KAccelManagerAlgorithm::CHECKABLE_GROUP_BOX_WEIGHT; } else { weight = KAccelManagerAlgorithm::GROUP_BOX_WEIGHT; } } i->m_content = KAccelString(content, weight); item->addChild(i); } } traverseChildren(w, item); } void KAcceleratorManagerPrivate::manageTabBar(QTabBar *bar, Item *item) { // ignore QTabBar for QDockWidgets, because QDockWidget on its title change // also updates its tabbar entry, so on the next run of KCheckAccelerators // this looks like a conflict and triggers a new reset of the shortcuts -> endless loop QWidget *parentWidget = bar->parentWidget(); if (parentWidget) { QMainWindow *mainWindow = qobject_cast(parentWidget); // TODO: find better hints that this is a QTabBar for QDockWidgets if (mainWindow) { // && (mainWindow->layout()->indexOf(bar) != -1)) QMainWindowLayout lacks proper support return; } } for (int i = 0; i < bar->count(); i++) { QString content = bar->tabText(i); if (content.isEmpty()) { continue; } Item *it = new Item; item->addChild(it); it->m_widget = bar; it->m_index = i; it->m_content = KAccelString(content); } } void KAcceleratorManagerPrivate::manageDockWidget(QDockWidget *dock, Item *item) { // As of Qt 4.4.3 setting a shortcut to a QDockWidget has no effect, // because a QDockWidget does not grab it, even while displaying an underscore // in the title for the given shortcut letter. // Still it is useful to set the shortcut, because if QDockWidgets are tabbed, // the tab automatically gets the same text as the QDockWidget title, including the shortcut. // And for the QTabBar the shortcut does work, it gets grabbed as usual. // Having the QDockWidget without a shortcut and resetting the tab text with a title including // the shortcut does not work, the tab text is instantly reverted to the QDockWidget title // (see also manageTabBar()). // All in all QDockWidgets and shortcuts are a little broken for now. QString content = dock->windowTitle(); if (content.isEmpty()) { return; } Item *it = new Item; item->addChild(it); it->m_widget = dock; it->m_content = KAccelString(content, KAccelManagerAlgorithm::STANDARD_ACCEL); } void KAcceleratorManagerPrivate::manageMenuBar(QMenuBar *mbar, Item *item) { QAction *maction; QString s; for (int i = 0; i < mbar->actions().count(); ++i) { maction = mbar->actions()[i]; if (!maction) { continue; } // nothing to do for separators if (maction->isSeparator()) { continue; } s = maction->text(); if (!s.isEmpty()) { Item *it = new Item; item->addChild(it); it->m_content = KAccelString(s, // menu titles are important, so raise the weight KAccelManagerAlgorithm::MENU_TITLE_WEIGHT); it->m_widget = mbar; it->m_index = i; } // have a look at the popup as well, if present if (maction->menu()) { KPopupAccelManager::manage(maction->menu()); } } } /********************************************************************* class KAcceleratorManager - main entry point This class is just here to provide a clean public API... *********************************************************************/ void KAcceleratorManager::manage(QWidget *widget, bool programmers_mode) { KAcceleratorManagerPrivate::changed_string.clear(); KAcceleratorManagerPrivate::added_string.clear(); KAcceleratorManagerPrivate::removed_string.clear(); KAcceleratorManagerPrivate::programmers_mode = programmers_mode; KAcceleratorManagerPrivate::manage(widget); } void KAcceleratorManager::last_manage(QString &added, QString &changed, QString &removed) { added = KAcceleratorManagerPrivate::added_string; changed = KAcceleratorManagerPrivate::changed_string; removed = KAcceleratorManagerPrivate::removed_string; } /********************************************************************* class KAccelString - a string with weighted characters *********************************************************************/ KAccelString::KAccelString(const QString &input, int initialWeight) : m_pureText(input), m_weight() { m_orig_accel = m_pureText.indexOf(QStringLiteral("(!)&")); if (m_orig_accel != -1) { m_pureText.remove(m_orig_accel, 4); } m_orig_accel = m_pureText.indexOf(QStringLiteral("(&&)")); if (m_orig_accel != -1) { m_pureText.replace(m_orig_accel, 4, QStringLiteral("&")); } m_origText = m_pureText; if (m_pureText.contains(QLatin1Char('\t'))) { m_pureText = m_pureText.left(m_pureText.indexOf(QLatin1Char('\t'))); } m_orig_accel = m_accel = stripAccelerator(m_pureText); if (initialWeight == -1) { initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT; } calculateWeights(initialWeight); // dump(); } QString KAccelString::accelerated() const { QString result = m_origText; if (result.isEmpty()) { return result; } if (KAcceleratorManagerPrivate::programmers_mode) { if (m_accel != m_orig_accel) { int oa = m_orig_accel; if (m_accel >= 0) { result.insert(m_accel, QStringLiteral("(!)&")); if (m_accel < m_orig_accel) { oa += 4; } } if (m_orig_accel >= 0) { result.replace(oa, 1, QStringLiteral("(&&)")); } } } else { if (m_accel >= 0 && m_orig_accel != m_accel) { if (m_orig_accel != -1) { result.remove(m_orig_accel, 1); } result.insert(m_accel, QStringLiteral("&")); } } return result; } QChar KAccelString::accelerator() const { if ((m_accel < 0) || (m_accel > m_pureText.length())) { return QChar(); } return m_pureText[m_accel].toLower(); } void KAccelString::calculateWeights(int initialWeight) { m_weight.resize(m_pureText.length()); int pos = 0; bool start_character = true; while (pos < m_pureText.length()) { QChar c = m_pureText[pos]; int weight = initialWeight + 1; // add special weight to first character if (pos == 0) { weight += KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT; } // add weight to word beginnings if (start_character) { weight += KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT; start_character = false; } // add decreasing weight to left characters if (pos < 50) { weight += (50 - pos); } // try to preserve the wanted accelerators if (pos == accel()) { weight += KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT; // qCDebug(KWidgetsAddonsLog) << "wanted " << m_pureText << " " << KAcceleratorManagerPrivate::standardName(m_origText); if (KAcceleratorManagerPrivate::standardName(m_origText)) { weight += KAccelManagerAlgorithm::STANDARD_ACCEL; } } // skip non typeable characters if (!c.isLetterOrNumber()) { weight = 0; start_character = true; } m_weight[pos] = weight; ++pos; } } int KAccelString::stripAccelerator(QString &text) { // Note: this code is derived from QAccel::shortcutKey int p = 0; while (p >= 0) { p = text.indexOf(QLatin1Char('&'), p) + 1; if (p <= 0 || p >= text.length()) { break; } if (text[p] != QLatin1Char('&')) { QChar c = text[p]; if (c.isPrint()) { text.remove(p - 1, 1); return p - 1; } } p++; } return -1; } int KAccelString::maxWeight(int &index, const QString &used) const { int max = 0; index = -1; for (int pos = 0; pos < m_pureText.length(); ++pos) if (used.indexOf(m_pureText[pos], 0, Qt::CaseInsensitive) == -1 && m_pureText[pos].toLatin1() != 0) if (m_weight[pos] > max) { max = m_weight[pos]; index = pos; } return max; } void KAccelString::dump() { QString s; for (int i = 0; i < m_weight.count(); ++i) { s += QStringLiteral("%1(%2) ").arg(pure()[i]).arg(m_weight[i]); } qCDebug(KWidgetsAddonsLog) << "s " << s; } /********************************************************************* findAccelerators - the algorithm determining the new accelerators The algorithm is very crude: * each character in each widget text is assigned a weight * the character with the highest weight over all is picked * that widget is removed from the list * the weights are recalculated * the process is repeated until no more accelerators can be found The algorithm has some advantages: * it favors 'nice' accelerators (first characters in a word, etc.) * it is quite fast, O(N²) * it is easy to understand :-) The disadvantages: * it does not try to find as many accelerators as possible TODO: * The result is always correct, but not necessarily optimal. Perhaps it would be a good idea to add another algorithm with higher complexity that gets used when this one fails, i.e. leaves widgets without accelerators. * The weights probably need some tweaking so they make more sense. *********************************************************************/ void KAccelManagerAlgorithm::findAccelerators(KAccelStringList &result, QString &used) { KAccelStringList accel_strings = result; // initially remove all accelerators for (KAccelStringList::Iterator it = result.begin(), total = result.end(); it != total; ++it) { (*it).setAccel(-1); } // pick the highest bids for (int cnt = 0; cnt < accel_strings.count(); ++cnt) { int max = 0, index = -1, accel = -1; // find maximum weight for (int i = 0; i < accel_strings.count(); ++i) { int a; int m = accel_strings[i].maxWeight(a, used); if (m > max) { max = m; index = i; accel = a; } } // stop if no more accelerators can be found if (index < 0) { return; } // insert the accelerator if (accel >= 0) { result[index].setAccel(accel); used.append(result[index].accelerator()); } // make sure we don't visit this one again accel_strings[index] = KAccelString(); } } /********************************************************************* class KPopupAccelManager - managing QMenu widgets dynamically *********************************************************************/ KPopupAccelManager::KPopupAccelManager(QMenu *popup) : QObject(popup), m_popup(popup), m_count(-1) { aboutToShow(); // do one check and then connect to show connect(popup, &QMenu::aboutToShow, this, &KPopupAccelManager::aboutToShow); } void KPopupAccelManager::aboutToShow() { // Note: we try to be smart and avoid recalculating the accelerators // whenever possible. Unfortunately, there is no way to know if an // item has been added or removed, so we can not do much more than // to compare the items each time the menu is shown :-( if (m_count != m_popup->actions().count()) { findMenuEntries(m_entries); calculateAccelerators(); m_count = m_popup->actions().count(); } else { KAccelStringList entries; findMenuEntries(entries); if (entries != m_entries) { m_entries = entries; calculateAccelerators(); } } } void KPopupAccelManager::calculateAccelerators() { // find the new accelerators QString used; KAccelManagerAlgorithm::findAccelerators(m_entries, used); // change the menu entries setMenuEntries(m_entries); } void KPopupAccelManager::findMenuEntries(KAccelStringList &list) { QString s; list.clear(); // read out the menu entries Q_FOREACH (QAction *maction, m_popup->actions()) { if (maction->isSeparator()) { continue; } s = maction->text(); // in full menus, look at entries with global accelerators last int weight = 50; if (s.contains(QLatin1Char('\t'))) { weight = 0; } list.append(KAccelString(s, weight)); // have a look at the popup as well, if present if (maction->menu()) { KPopupAccelManager::manage(maction->menu()); } } } // Duplicated from qaction.cpp static QString copy_of_qt_strippedText(QString s) { s.remove(QStringLiteral("...")); for (int i = 0; i < s.size(); ++i) { if (s.at(i) == QLatin1Char('&')) { s.remove(i, 1); } } return s.trimmed(); } void KPopupAccelManager::setMenuEntries(const KAccelStringList &list) { uint cnt = 0; Q_FOREACH (QAction *maction, m_popup->actions()) { if (maction->isSeparator()) { continue; } QString iconText = maction->iconText(); const QString oldText = maction->text(); // Check if iconText was generated by Qt. In that case ignore it (no support for CJK accelerators) and set it from the text. if (iconText == copy_of_qt_strippedText(oldText)) { iconText = removeAcceleratorMarker(oldText); if (iconText != maction->iconText()) { maction->setIconText(iconText); } } if (KAcceleratorManagerPrivate::checkChange(list[cnt])) { maction->setText(list[cnt].accelerated()); } cnt++; } } void KPopupAccelManager::manage(QMenu *popup) { // don't add more than one manager to a popup if (popup->findChild(QString()) == nullptr) { new KPopupAccelManager(popup); } } void QWidgetStackAccelManager::manage(QStackedWidget *stack) { if (stack->findChild(QString()) == nullptr) { new QWidgetStackAccelManager(stack); } } QWidgetStackAccelManager::QWidgetStackAccelManager(QStackedWidget *stack) : QObject(stack), m_stack(stack) { currentChanged(stack->currentIndex()); // do one check and then connect to show connect(stack, &QStackedWidget::currentChanged, this, &QWidgetStackAccelManager::currentChanged); } bool QWidgetStackAccelManager::eventFilter(QObject *watched, QEvent *e) { if (e->type() == QEvent::Show && qApp->activeWindow()) { KAcceleratorManager::manage(qApp->activeWindow()); watched->removeEventFilter(this); } return false; } void QWidgetStackAccelManager::currentChanged(int child) { if (child < 0 || child >= static_cast(parent())->count()) { // NOTE: QStackedWidget emits currentChanged(-1) when it is emptied return; } static_cast(parent())->widget(child)->installEventFilter(this); } void KAcceleratorManager::setNoAccel(QWidget *widget) { KAcceleratorManagerPrivate::ignored_widgets[widget] = 1; } void KAcceleratorManager::addStandardActionNames(const QStringList &names) { KAcceleratorManagerPrivate::addStandardActionNames(names); } #include "moc_kacceleratormanager_p.cpp" diff --git a/src/kactionselector.cpp b/src/kactionselector.cpp index 5381095..d26ac91 100644 --- a/src/kactionselector.cpp +++ b/src/kactionselector.cpp @@ -1,571 +1,572 @@ /* This file is part of the KDE project Copyright (C) 2002 Anders Lund This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kactionselector.h" #include #include #include -#include -#include #include +#include +#include +#include class KActionSelectorPrivate { public: KActionSelectorPrivate(KActionSelector *q): q(q) {} KActionSelector *q = nullptr; QListWidget *availableListWidget = nullptr; QListWidget *selectedListWidget = nullptr; QToolButton *btnAdd = nullptr; QToolButton *btnRemove = nullptr; QToolButton *btnUp = nullptr; QToolButton *btnDown = nullptr; QLabel *lAvailable = nullptr; QLabel *lSelected = nullptr; bool moveOnDoubleClick : 1; bool keyboardEnabled : 1; bool showUpDownButtons : 1; QString addIcon, removeIcon, upIcon, downIcon; KActionSelector::InsertionPolicy availableInsertionPolicy, selectedInsertionPolicy; /** Move item @p item to the other listbox */ void moveItem(QListWidgetItem *item); /** loads the icons for the move buttons. */ void loadIcons(); /** @return the index to insert an item into listbox @p lb, given InsertionPolicy @p policy. Note that if policy is Sorted, this will return -1. Sort the listbox after inserting the item in that case. */ int insertionIndex(QListWidget *lb, KActionSelector::InsertionPolicy policy); /** @return the index of the first selected item in listbox @p lb. If no item is selected, it will return -1. */ int selectedRowIndex(QListWidget *lb); void buttonAddClicked(); void buttonRemoveClicked(); void buttonUpClicked(); void buttonDownClicked(); void itemDoubleClicked(QListWidgetItem *item); void slotCurrentChanged(QListWidgetItem *) { q->setButtonsEnabled(); } }; //BEGIN Constructor/destructor KActionSelector::KActionSelector(QWidget *parent) : QWidget(parent) , d(new KActionSelectorPrivate(this)) { d->moveOnDoubleClick = true; d->keyboardEnabled = true; d->addIcon = QLatin1String(QApplication::isRightToLeft() ? "go-previous" : "go-next"); d->removeIcon = QLatin1String(QApplication::isRightToLeft() ? "go-next" : "go-previous"); d->upIcon = QStringLiteral("go-up"); d->downIcon = QStringLiteral("go-down"); d->availableInsertionPolicy = Sorted; d->selectedInsertionPolicy = BelowCurrent; d->showUpDownButtons = true; QHBoxLayout *lo = new QHBoxLayout(this); lo->setContentsMargins(0, 0, 0, 0); QVBoxLayout *loAv = new QVBoxLayout(); lo->addLayout(loAv); d->lAvailable = new QLabel(tr("&Available:"), this); loAv->addWidget(d->lAvailable); d->availableListWidget = new QListWidget(this); loAv->addWidget(d->availableListWidget); d->lAvailable->setBuddy(d->availableListWidget); QVBoxLayout *loHBtns = new QVBoxLayout(); lo->addLayout(loHBtns); loHBtns->addStretch(1); d->btnAdd = new QToolButton(this); loHBtns->addWidget(d->btnAdd); d->btnRemove = new QToolButton(this); loHBtns->addWidget(d->btnRemove); loHBtns->addStretch(1); QVBoxLayout *loS = new QVBoxLayout(); lo->addLayout(loS); d->lSelected = new QLabel(tr("&Selected:"), this); loS->addWidget(d->lSelected); d->selectedListWidget = new QListWidget(this); loS->addWidget(d->selectedListWidget); d->lSelected->setBuddy(d->selectedListWidget); QVBoxLayout *loVBtns = new QVBoxLayout(); lo->addLayout(loVBtns); loVBtns->addStretch(1); d->btnUp = new QToolButton(this); d->btnUp->setAutoRepeat(true); loVBtns->addWidget(d->btnUp); d->btnDown = new QToolButton(this); d->btnDown->setAutoRepeat(true); loVBtns->addWidget(d->btnDown); loVBtns->addStretch(1); d->loadIcons(); connect(d->btnAdd, &QToolButton::clicked, this, [this]() { d->buttonAddClicked(); }); connect(d->btnRemove, &QToolButton::clicked, this, [this]() { d->buttonRemoveClicked(); }); connect(d->btnUp, &QToolButton::clicked, this, [this]() { d->buttonUpClicked(); }); connect(d->btnDown, &QToolButton::clicked, this, [this]() { d->buttonDownClicked(); }); connect(d->availableListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(itemDoubleClicked(QListWidgetItem*))); connect(d->selectedListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(itemDoubleClicked(QListWidgetItem*))); connect(d->availableListWidget, &QListWidget::itemSelectionChanged, this, &KActionSelector::setButtonsEnabled); connect(d->selectedListWidget, &QListWidget::itemSelectionChanged, this, &KActionSelector::setButtonsEnabled); d->availableListWidget->installEventFilter(this); d->selectedListWidget->installEventFilter(this); setButtonsEnabled(); } KActionSelector::~KActionSelector() { delete d; } //END Constructor/destroctor //BEGIN Public Methods QListWidget *KActionSelector::availableListWidget() const { return d->availableListWidget; } QListWidget *KActionSelector::selectedListWidget() const { return d->selectedListWidget; } void KActionSelector::setButtonIcon(const QString &icon, MoveButton button) { switch (button) { case ButtonAdd: d->addIcon = icon; d->btnAdd->setIcon(QIcon::fromTheme(icon)); break; case ButtonRemove: d->removeIcon = icon; d->btnRemove->setIcon(QIcon::fromTheme(icon)); break; case ButtonUp: d->upIcon = icon; d->btnUp->setIcon(QIcon::fromTheme(icon)); break; case ButtonDown: d->downIcon = icon; d->btnDown->setIcon(QIcon::fromTheme(icon)); break; default: // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonIcon: DAINBREAD!"; break; } } void KActionSelector::setButtonIconSet(const QIcon &iconset, MoveButton button) { switch (button) { case ButtonAdd: d->btnAdd->setIcon(iconset); break; case ButtonRemove: d->btnRemove->setIcon(iconset); break; case ButtonUp: d->btnUp->setIcon(iconset); break; case ButtonDown: d->btnDown->setIcon(iconset); break; default: // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonIconSet: DAINBREAD!"; break; } } void KActionSelector::setButtonTooltip(const QString &tip, MoveButton button) { switch (button) { case ButtonAdd: d->btnAdd->setText(tip); d->btnAdd->setToolTip(tip); break; case ButtonRemove: d->btnRemove->setText(tip); d->btnRemove->setToolTip(tip); break; case ButtonUp: d->btnUp->setText(tip); d->btnUp->setToolTip(tip); break; case ButtonDown: d->btnDown->setText(tip); d->btnDown->setToolTip(tip); break; default: // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonToolTip: DAINBREAD!"; break; } } void KActionSelector::setButtonWhatsThis(const QString &text, MoveButton button) { switch (button) { case ButtonAdd: d->btnAdd->setWhatsThis(text); break; case ButtonRemove: d->btnRemove->setWhatsThis(text); break; case ButtonUp: d->btnUp->setWhatsThis(text); break; case ButtonDown: d->btnDown->setWhatsThis(text); break; default: // qCDebug(KWidgetsAddonsLog)<<"KActionSelector::setButtonWhatsThis: DAINBREAD!"; break; } } //END Public Methods //BEGIN Properties bool KActionSelector::moveOnDoubleClick() const { return d->moveOnDoubleClick; } void KActionSelector::setMoveOnDoubleClick(bool b) { d->moveOnDoubleClick = b; } bool KActionSelector::keyboardEnabled() const { return d->keyboardEnabled; } void KActionSelector::setKeyboardEnabled(bool b) { d->keyboardEnabled = b; } QString KActionSelector::availableLabel() const { return d->lAvailable->text(); } void KActionSelector::setAvailableLabel(const QString &text) { d->lAvailable->setText(text); } QString KActionSelector::selectedLabel() const { return d->lSelected->text(); } void KActionSelector::setSelectedLabel(const QString &text) { d->lSelected->setText(text); } KActionSelector::InsertionPolicy KActionSelector::availableInsertionPolicy() const { return d->availableInsertionPolicy; } void KActionSelector::setAvailableInsertionPolicy(InsertionPolicy p) { d->availableInsertionPolicy = p; } KActionSelector::InsertionPolicy KActionSelector::selectedInsertionPolicy() const { return d->selectedInsertionPolicy; } void KActionSelector::setSelectedInsertionPolicy(InsertionPolicy p) { d->selectedInsertionPolicy = p; } bool KActionSelector::showUpDownButtons() const { return d->showUpDownButtons; } void KActionSelector::setShowUpDownButtons(bool show) { d->showUpDownButtons = show; if (show) { d->btnUp->show(); d->btnDown->show(); } else { d->btnUp->hide(); d->btnDown->hide(); } } //END Properties //BEGIN Public Slots void KActionSelector::setButtonsEnabled() { d->btnAdd->setEnabled(d->selectedRowIndex(d->availableListWidget) > -1); d->btnRemove->setEnabled(d->selectedRowIndex(d->selectedListWidget) > -1); d->btnUp->setEnabled(d->selectedRowIndex(d->selectedListWidget) > 0); d->btnDown->setEnabled(d->selectedRowIndex(d->selectedListWidget) > -1 && d->selectedRowIndex(d->selectedListWidget) < d->selectedListWidget->count() - 1); } //END Public Slots //BEGIN Protected void KActionSelector::keyPressEvent(QKeyEvent *e) { if (! d->keyboardEnabled) { return; } if ((e->modifiers() & Qt::ControlModifier)) { switch (e->key()) { case Qt::Key_Right: d->buttonAddClicked(); break; case Qt::Key_Left: d->buttonRemoveClicked(); break; case Qt::Key_Up: d->buttonUpClicked(); break; case Qt::Key_Down: d->buttonDownClicked(); break; default: e->ignore(); return; } } } bool KActionSelector::eventFilter(QObject *o, QEvent *e) { if (d->keyboardEnabled && e->type() == QEvent::KeyPress) { if ((((QKeyEvent *)e)->modifiers() & Qt::ControlModifier)) { switch (((QKeyEvent *)e)->key()) { case Qt::Key_Right: d->buttonAddClicked(); break; case Qt::Key_Left: d->buttonRemoveClicked(); break; case Qt::Key_Up: d->buttonUpClicked(); break; case Qt::Key_Down: d->buttonDownClicked(); break; default: return QWidget::eventFilter(o, e); } return true; } else if (QListWidget *lb = qobject_cast(o)) { switch (((QKeyEvent *)e)->key()) { case Qt::Key_Return: case Qt::Key_Enter: int index = lb->currentRow(); if (index < 0) { break; } d->moveItem(lb->item(index)); return true; } } } return QWidget::eventFilter(o, e); } //END Protected //BEGIN Private Slots void KActionSelectorPrivate::buttonAddClicked() { // move all selected items from available to selected listbox QList list = availableListWidget->selectedItems(); Q_FOREACH (QListWidgetItem *item, list) { availableListWidget->takeItem(availableListWidget->row(item)); selectedListWidget->insertItem(insertionIndex(selectedListWidget, selectedInsertionPolicy), item); selectedListWidget->setCurrentItem(item); emit q->added(item); } if (selectedInsertionPolicy == KActionSelector::Sorted) { selectedListWidget->sortItems(); } selectedListWidget->setFocus(); } void KActionSelectorPrivate::buttonRemoveClicked() { // move all selected items from selected to available listbox QList list = selectedListWidget->selectedItems(); Q_FOREACH (QListWidgetItem *item, list) { selectedListWidget->takeItem(selectedListWidget->row(item)); availableListWidget->insertItem(insertionIndex(availableListWidget, availableInsertionPolicy), item); availableListWidget->setCurrentItem(item); emit q->removed(item); } if (availableInsertionPolicy == KActionSelector::Sorted) { availableListWidget->sortItems(); } availableListWidget->setFocus(); } void KActionSelectorPrivate::buttonUpClicked() { int c = selectedRowIndex(selectedListWidget); if (c < 1) { return; } QListWidgetItem *item = selectedListWidget->item(c); selectedListWidget->takeItem(c); selectedListWidget->insertItem(c - 1, item); selectedListWidget->setCurrentItem(item); emit q->movedUp(item); } void KActionSelectorPrivate::buttonDownClicked() { int c = selectedRowIndex(selectedListWidget); if (c < 0 || c == selectedListWidget->count() - 1) { return; } QListWidgetItem *item = selectedListWidget->item(c); selectedListWidget->takeItem(c); selectedListWidget->insertItem(c + 1, item); selectedListWidget->setCurrentItem(item); emit q->movedDown(item); } void KActionSelectorPrivate::itemDoubleClicked(QListWidgetItem *item) { if (moveOnDoubleClick) { moveItem(item); } } //END Private Slots //BEGIN Private Methods void KActionSelectorPrivate::loadIcons() { btnAdd->setIcon(QIcon::fromTheme(addIcon)); btnRemove->setIcon(QIcon::fromTheme(removeIcon)); btnUp->setIcon(QIcon::fromTheme(upIcon)); btnDown->setIcon(QIcon::fromTheme(downIcon)); } void KActionSelectorPrivate::moveItem(QListWidgetItem *item) { QListWidget *lbFrom = item->listWidget(); QListWidget *lbTo; if (lbFrom == availableListWidget) { lbTo = selectedListWidget; } else if (lbFrom == selectedListWidget) { lbTo = availableListWidget; } else { //?! somewhat unlikely... return; } KActionSelector::InsertionPolicy p = (lbTo == availableListWidget) ? availableInsertionPolicy : selectedInsertionPolicy; lbFrom->takeItem(lbFrom->row(item)); lbTo->insertItem(insertionIndex(lbTo, p), item); lbTo->setFocus(); lbTo->setCurrentItem(item); if (p == KActionSelector::Sorted) { lbTo->sortItems(); } if (lbTo == selectedListWidget) { emit q->added(item); } else { emit q->removed(item); } } int KActionSelectorPrivate::insertionIndex(QListWidget *lb, KActionSelector::InsertionPolicy policy) { int index; switch (policy) { case KActionSelector::BelowCurrent: index = lb->currentRow(); if (index > -1) { index += 1; } break; case KActionSelector::AtTop: index = 0; break; case KActionSelector::AtBottom: index = lb->count(); break; default: index = -1; } return index; } int KActionSelectorPrivate::selectedRowIndex(QListWidget *lb) { QList list = lb->selectedItems(); if (list.isEmpty()) { return -1; } return lb->row(list.at(0)); } //END Private Methods #include "moc_kactionselector.cpp" diff --git a/src/kbusyindicatorwidget.cpp b/src/kbusyindicatorwidget.cpp index ee1e12a..139ea88 100644 --- a/src/kbusyindicatorwidget.cpp +++ b/src/kbusyindicatorwidget.cpp @@ -1,109 +1,109 @@ /* Copyright 2019 Harald Sitter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "kbusyindicatorwidget.h" #include #include #include -#include #include #include +#include class KBusyIndicatorWidgetPrivate { public: KBusyIndicatorWidgetPrivate(KBusyIndicatorWidget *parent) : q(parent) { animation.setLoopCount(-1); animation.setDuration(1500); animation.setStartValue(0); animation.setEndValue(360); QObject::connect(&animation, &QVariantAnimation::valueChanged, q, [=](QVariant value) { rotation = value.toReal(); q->update(); // repaint new rotation }); } KBusyIndicatorWidget *q = nullptr; QVariantAnimation animation; QIcon icon = QIcon::fromTheme(QStringLiteral("view-refresh")); qreal rotation = 0; QPointF paintCenter; }; KBusyIndicatorWidget::KBusyIndicatorWidget(QWidget *parent) : QWidget(parent) , d(new KBusyIndicatorWidgetPrivate(this)) { } KBusyIndicatorWidget::~KBusyIndicatorWidget() { delete d; } QSize KBusyIndicatorWidget::minimumSizeHint() const { const auto extent = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize); return QSize(extent, extent); } void KBusyIndicatorWidget::showEvent(QShowEvent *event) { QWidget::showEvent(event); d->animation.start(); } void KBusyIndicatorWidget::hideEvent(QHideEvent *event) { QWidget::hideEvent(event); d->animation.pause(); } void KBusyIndicatorWidget::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); d->paintCenter = QPointF(event->size().width() / 2.0, event->size().height() / 2.0); } void KBusyIndicatorWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); // Rotate around the center and then reset back to origin for icon painting. painter.translate(d->paintCenter); painter.rotate(d->rotation); painter.translate(-d->paintCenter); d->icon.paint(&painter, rect()); } bool KBusyIndicatorWidget::event(QEvent *event) { // Only overridden to be flexible WRT binary compatible in the future. // Overriding later has potential to change the call going through // the vtable or not. return QWidget::event(event); } diff --git a/src/kcapacitybar.cpp b/src/kcapacitybar.cpp index 6bc424f..444035d 100644 --- a/src/kcapacitybar.cpp +++ b/src/kcapacitybar.cpp @@ -1,385 +1,382 @@ /* * This file is part of the KDE project * Copyright (C) 2008 Rafael Fernández López * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kcapacitybar.h" #include "kstyleextensions.h" #include -#include -#include #include #include -#include #include #include #include -#include +#include #define ROUND_MARGIN 6 #define VERTICAL_SPACING 1 static const int LightShade = 100; static const int MidShade = 200; static const int DarkShade = 300; class Q_DECL_HIDDEN KCapacityBar::Private { public: Private(KCapacityBar::DrawTextMode drawTextMode) : value(0) , fillFullBlocks(true) , continuous(true) , barHeight(12) , horizontalTextAlignment(Qt::AlignCenter) , ce_capacityBar(QStyle::ControlElement(0)) , drawTextMode(drawTextMode) {} ~Private() {} QString text; int value; bool fillFullBlocks; bool continuous; int barHeight; Qt::Alignment horizontalTextAlignment; QStyle::ControlElement ce_capacityBar; KCapacityBar::DrawTextMode drawTextMode; }; KCapacityBar::KCapacityBar(QWidget *parent) : KCapacityBar(DrawTextOutline, parent) { } KCapacityBar::KCapacityBar(KCapacityBar::DrawTextMode drawTextMode, QWidget *parent) : QWidget(parent) , d(new Private(drawTextMode)) { d->ce_capacityBar = KStyleExtensions::customControlElement(QStringLiteral("CE_CapacityBar"), this); } KCapacityBar::~KCapacityBar() { delete d; } void KCapacityBar::setValue(int value) { d->value = value; update(); } int KCapacityBar::value() const { return d->value; } void KCapacityBar::setText(const QString &text) { bool updateGeom = d->text.isEmpty() || text.isEmpty(); d->text = text; if (updateGeom) { updateGeometry(); } #ifndef QT_NO_ACCESSIBILITY setAccessibleName(text); #endif update(); } QString KCapacityBar::text() const { return d->text; } void KCapacityBar::setFillFullBlocks(bool fillFullBlocks) { d->fillFullBlocks = fillFullBlocks; update(); } bool KCapacityBar::fillFullBlocks() const { return d->fillFullBlocks; } void KCapacityBar::setContinuous(bool continuous) { d->continuous = continuous; update(); } bool KCapacityBar::continuous() const { return d->continuous; } void KCapacityBar::setBarHeight(int barHeight) { // automatically convert odd values to even. This will make the bar look // better. d->barHeight = (barHeight % 2) ? barHeight + 1 : barHeight; updateGeometry(); } int KCapacityBar::barHeight() const { return d->barHeight; } void KCapacityBar::setHorizontalTextAlignment(Qt::Alignment horizontalTextAlignment) { Qt::Alignment alignment = horizontalTextAlignment; // if the value came with any vertical alignment flag, remove it. alignment &= ~Qt::AlignTop; alignment &= ~Qt::AlignBottom; alignment &= ~Qt::AlignVCenter; d->horizontalTextAlignment = alignment; update(); } Qt::Alignment KCapacityBar::horizontalTextAlignment() const { return d->horizontalTextAlignment; } void KCapacityBar::setDrawTextMode(DrawTextMode mode) { d->drawTextMode = mode; update(); } KCapacityBar::DrawTextMode KCapacityBar::drawTextMode() const { return d->drawTextMode; } void KCapacityBar::drawCapacityBar(QPainter *p, const QRect &rect) const { if (d->ce_capacityBar) { QStyleOptionProgressBar opt; opt.initFrom(this); opt.rect = rect; opt.minimum = 0; opt.maximum = 100; opt.progress = d->value; opt.state |= QStyle::State_Horizontal; opt.text = d->text; opt.textAlignment = Qt::AlignCenter; opt.textVisible = true; style()->drawControl(d->ce_capacityBar, &opt, p, this); return; } p->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); p->save(); QRect drawRect(rect); if (d->drawTextMode == DrawTextOutline) { drawRect.setHeight(d->barHeight); } QPainterPath outline; outline.moveTo(rect.left() + ROUND_MARGIN / 4 + 1, rect.top()); outline.lineTo(rect.left() + drawRect.width() - ROUND_MARGIN / 4 - 1, rect.top()); outline.quadTo(rect.left() + drawRect.width() + ROUND_MARGIN / 2, drawRect.height() / 2 + rect.top(), rect.left() + drawRect.width() - ROUND_MARGIN / 4 - 1, drawRect.height() + rect.top()); outline.lineTo(rect.left() + ROUND_MARGIN / 4 + 1, drawRect.height() + rect.top()); outline.quadTo(-ROUND_MARGIN / 2 + rect.left(), drawRect.height() / 2 + rect.top(), rect.left() + ROUND_MARGIN / 4 + 1, rect.top()); const QColor fillColor = palette().window().color().darker(DarkShade); p->fillPath(outline, QColor(fillColor.red(), fillColor.green(), fillColor.blue(), 50)); QRadialGradient bottomGradient(QPointF(rect.width() / 2, drawRect.bottom() + 1), rect.width() / 2); bottomGradient.setColorAt(0, palette().window().color().darker(LightShade)); bottomGradient.setColorAt(1, Qt::transparent); p->fillRect(QRect(rect.left(), drawRect.bottom() + rect.top(), rect.width(), 1), bottomGradient); p->translate(rect.left() + 2, rect.top() + 1); drawRect.setWidth(drawRect.width() - 4); drawRect.setHeight(drawRect.height() - 2); QPainterPath path; path.moveTo(ROUND_MARGIN / 4, 0); path.lineTo(drawRect.width() - ROUND_MARGIN / 4, 0); path.quadTo(drawRect.width() + ROUND_MARGIN / 2, drawRect.height() / 2, drawRect.width() - ROUND_MARGIN / 4, drawRect.height()); path.lineTo(ROUND_MARGIN / 4, drawRect.height()); path.quadTo(-ROUND_MARGIN / 2, drawRect.height() / 2, ROUND_MARGIN / 4, 0); QLinearGradient linearGradient(0, 0, 0, drawRect.height()); linearGradient.setColorAt(0.5, palette().window().color().darker(MidShade)); linearGradient.setColorAt(1, palette().window().color().darker(LightShade)); p->fillPath(path, linearGradient); p->setBrush(Qt::NoBrush); p->setPen(Qt::NoPen); if (d->continuous || !d->fillFullBlocks) { int start = (layoutDirection() == Qt::LeftToRight) ? -1 : (drawRect.width() + 2) - (drawRect.width() + 2) * (d->value / 100.0); p->setClipRect(QRect(start, 0, (drawRect.width() + 2) * (d->value / 100.0), drawRect.height()), Qt::IntersectClip); } int left = (layoutDirection() == Qt::LeftToRight) ? 0 : drawRect.width(); int right = (layoutDirection() == Qt::LeftToRight) ? drawRect.width() : 0; int roundMargin = (layoutDirection() == Qt::LeftToRight) ? ROUND_MARGIN : -ROUND_MARGIN; int spacing = 2; int verticalSpacing = VERTICAL_SPACING; int slotWidth = 6; int start = roundMargin / 4; QPainterPath internalBar; internalBar.moveTo(left + roundMargin / 4, 0); internalBar.lineTo(right - roundMargin / 4, 0); internalBar.quadTo(right + roundMargin / 2, drawRect.height() / 2, right - roundMargin / 4, drawRect.height()); internalBar.lineTo(left + roundMargin / 4, drawRect.height()); internalBar.quadTo(left - roundMargin / 2, drawRect.height() / 2, left + roundMargin / 4, 0); QLinearGradient fillInternalBar(left, 0, right, 0); fillInternalBar.setColorAt(0, palette().window().color().darker(MidShade)); fillInternalBar.setColorAt(0.5, palette().window().color().darker(LightShade)); fillInternalBar.setColorAt(1, palette().window().color().darker(MidShade)); if (d->drawTextMode == KCapacityBar::DrawTextInline) { p->save(); p->setOpacity(p->opacity() * 0.7); } if (!d->continuous) { int numSlots = (drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) / (slotWidth + spacing); int stopSlot = floor((numSlots + 2) * (d->value / 100.0)); int plusOffset = d->fillFullBlocks ? ((drawRect.width() - ROUND_MARGIN - ((slotWidth + spacing) * 2)) - (numSlots * (slotWidth + spacing))) / 2.0 : 0; if (!d->fillFullBlocks || stopSlot) { QPainterPath firstSlot; firstSlot.moveTo(left + roundMargin / 4, verticalSpacing); firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, verticalSpacing); firstSlot.lineTo(left + slotWidth + roundMargin / 4 + plusOffset, drawRect.height() - verticalSpacing); firstSlot.lineTo(left + roundMargin / 4, drawRect.height() - verticalSpacing); firstSlot.quadTo(left, drawRect.height() / 2, left + roundMargin / 4, verticalSpacing); p->fillPath(firstSlot, fillInternalBar); start += slotWidth + spacing + plusOffset; bool stopped = false; for (int i = 0; i < numSlots + 1; i++) { if (d->fillFullBlocks && (i == (stopSlot + 1))) { stopped = true; break; } p->fillRect(QRect(rect.left() + start, rect.top() + verticalSpacing, slotWidth, drawRect.height() - verticalSpacing * 2), fillInternalBar); start += slotWidth + spacing; } if (!d->fillFullBlocks || (!stopped && (stopSlot != (numSlots + 1)) && (stopSlot != numSlots))) { QPainterPath lastSlot; lastSlot.moveTo(start, verticalSpacing); lastSlot.lineTo(start, drawRect.height() - verticalSpacing); lastSlot.lineTo(start + slotWidth + plusOffset, drawRect.height() - verticalSpacing); lastSlot.quadTo(start + roundMargin, drawRect.height() / 2, start + slotWidth + plusOffset, verticalSpacing); lastSlot.lineTo(start, verticalSpacing); p->fillPath(lastSlot, fillInternalBar); } } } else { p->fillPath(internalBar, fillInternalBar); } if (d->drawTextMode == KCapacityBar::DrawTextInline) { p->restore(); } p->save(); p->setClipping(false); QRadialGradient topGradient(QPointF(rect.width() / 2, drawRect.top()), rect.width() / 2); const QColor fillTopColor = palette().window().color().darker(LightShade); topGradient.setColorAt(0, QColor(fillTopColor.red(), fillTopColor.green(), fillTopColor.blue(), 127)); topGradient.setColorAt(1, Qt::transparent); p->fillRect(QRect(rect.left(), rect.top() + drawRect.top(), rect.width(), 2), topGradient); p->restore(); p->save(); p->setClipRect(QRect(-1, 0, rect.width(), drawRect.height() / 2), Qt::ReplaceClip); QLinearGradient glassGradient(0, -5, 0, drawRect.height()); const QColor fillGlassColor = palette().base().color(); glassGradient.setColorAt(0, QColor(fillGlassColor.red(), fillGlassColor.green(), fillGlassColor.blue(), 255)); glassGradient.setColorAt(1, Qt::transparent); p->fillPath(internalBar, glassGradient); p->restore(); p->restore(); if (d->drawTextMode == KCapacityBar::DrawTextInline) { QRect rect(drawRect); rect.setHeight(rect.height() + 4); p->drawText(rect, Qt::AlignCenter, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width() - 2 * ROUND_MARGIN)); } else { p->drawText(rect, Qt::AlignBottom | d->horizontalTextAlignment, fontMetrics().elidedText(d->text, Qt::ElideRight, drawRect.width())); } } QSize KCapacityBar::minimumSizeHint() const { int width = (d->drawTextMode == KCapacityBar::DrawTextInline) ? fontMetrics().width(d->text) + ROUND_MARGIN * 2 : fontMetrics().width(d->text); int height = (d->drawTextMode == KCapacityBar::DrawTextInline) ? qMax(fontMetrics().height(), d->barHeight) : (d->text.isEmpty() ? 0 : fontMetrics().height() + VERTICAL_SPACING * 2) + d->barHeight; if (height % 2) { height++; } return QSize(width, height); } void KCapacityBar::paintEvent(QPaintEvent *event) { QPainter p(this); p.setClipRect(event->rect()); drawCapacityBar(&p, contentsRect()); p.end(); } void KCapacityBar::changeEvent(QEvent* event) { QWidget::changeEvent(event); if (event->type() == QEvent::StyleChange) { d->ce_capacityBar = KStyleExtensions::customControlElement(QStringLiteral("CE_CapacityBar"), this); } } diff --git a/src/kcharselect.h b/src/kcharselect.h index 71804f3..e578163 100644 --- a/src/kcharselect.h +++ b/src/kcharselect.h @@ -1,312 +1,311 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef kcharselect_h #define kcharselect_h #include -#include #include #include class QFont; class QUrl; /** * @class KCharSelect kcharselect.h KCharSelect * * @short Character selection widget * * This widget allows the user to select a character of a * specified font and to browse Unicode information * * \image html kcharselect.png "KCharSelect Widget" * * You can specify the font whose characters should be displayed via * setCurrentFont(). Using the Controls argument in the contructor * you can create a compact version of KCharSelect if there is not enough * space and if you don't need all features. * * KCharSelect displays one Unicode block at a time and provides * categorized access to them. Unicode character names and further details, * including cross references, are displayed. Additionally, there is a search * to find characters. * * By default, KCharSelect is restricted to Basic Multilingual Plane (BMP) * characters that QChar supports, i.e. characters with code points that * fit into a quint16 (U+0000..U+FFFF). API methods that have a QChar * argument can only be used for this default mode: * * To get the current selected character, use the currentChar() * method. You can set the character which should be displayed with * setCurrentChar(). * * If you want the user to select and search characters from all planes, * i.e. characters U+0000..U+10FFFF, use setAllPlanesEnabled(true) * and use the @c uint based methods currentCodePoint() and * setCurrentCodePoint() instead. * * Since QString does not allow @c uint code points, you either must * use QString::fromUcs4() and QString::ToUcs4() to convert between * strings and code points, or manually do the surrogate pair handling * using QChar::requiresSurrogates() and friends. * * @author Reginald Stadlbauer * @author Daniel Laidig */ class KWIDGETSADDONS_EXPORT KCharSelect : public QWidget { Q_OBJECT Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont) Q_PROPERTY(QChar currentChar READ currentChar WRITE setCurrentChar) Q_PROPERTY(uint currentCodePoint READ currentCodePoint WRITE setCurrentCodePoint NOTIFY currentCodePointChanged) Q_PROPERTY(QList displayedChars READ displayedChars) Q_PROPERTY(QVector displayedCodePoints READ displayedCodePoints) Q_PROPERTY(bool allPlanesEnabled READ allPlanesEnabled WRITE setAllPlanesEnabled DESIGNABLE true) public: /** * Flags to set the shown widgets */ enum Control { /** * Shows the search widgets */ SearchLine = 0x01, /** * Shows the font combo box */ FontCombo = 0x02, /** * Shows the font size spin box */ FontSize = 0x04, /** * Shows the category/block selection combo boxes */ BlockCombos = 0x08, /** * Shows the actual table */ CharacterTable = 0x10, /** * Shows the detail browser */ DetailBrowser = 0x20, /** * Shows the Back/Forward buttons */ HistoryButtons = 0x40, /** * Shows everything */ AllGuiElements = 65535 }; Q_DECLARE_FLAGS(Controls, Control) /** * Constructor. @p controls can be used to show a custom set of widgets. * * @param parent the parent widget for this KCharSelect (see QWidget documentation) * @param controls selects the visible controls on the KCharSelect widget * * @since 4.2 */ explicit KCharSelect( QWidget *parent, const Controls controls = AllGuiElements); /** * Constructor. @p controls can be used to show a custom set of widgets. * * The widget uses the following actions: * - KStandardActions::find() (edit_find) * - KStandardActions::back() (go_back) * - KStandardActions::forward() (go_forward) * * If you provide a KActionCollection, this will be populated with the above actions, * which you can then manually trigger or place in menus and toolbars. * * @param parent the parent widget for this KCharSelect (see QWidget documentation) * @param actionParent if this is not @c null, KCharSelect will place its actions into this * collection * @param controls selects the visible controls on the KCharSelect widget * * @since 4.2 */ explicit KCharSelect( QWidget *parent, QObject *actionParent, const Controls controls = AllGuiElements); ~KCharSelect() override; /** * Reimplemented. */ QSize sizeHint() const override; /** * Sets the allowed Unicode code planes. If @p all is @c false, then * only characters from the Basic Multilingual Plane (BMP) can be * selected, otherwise characters from all planes are allowed. * * For compatibility reasons, the default is @c false. * * If you enable support for all planes, you must use the functions * handling @c uint code points instead of @c QChar characters. * @since 5.25 */ void setAllPlanesEnabled(bool all); /** * @returns @c true, if characters from all Unicode code planes * can be selected. * @since 5.25 */ bool allPlanesEnabled() const; /** * Returns the currently selected character. If characters outside the * Basic Multilingual Plane (BMP) can be selected, use currentCodePoint * instead. * @sa currentCodePoint */ QChar currentChar() const; /** * Returns the Unicode code point of the currently selected character. * @warning If you enabled support for all Unicode planes, you must use * QChar::requiresSurrogates() to check if the code point requires * conversion to a UTF-16 surrogate pair before converting it to QString. * You cannot convert a code point to a QChar. * @since 5.25 */ uint currentCodePoint() const; /** * Returns the currently displayed font. */ QFont currentFont() const; /** * Returns a list of currently displayed characters. If characters outside the * Basic Multilingual Plane (BMP) can be selected, use displayedCodePoints * instead. * Warning: this method can be a bit slow * @sa displayedCodePoints */ QList displayedChars() const; /** * Returns a list of Unicode code points of the currently displayed characters. * @since 5.25 */ QVector displayedCodePoints() const; public Q_SLOTS: /** * Highlights the character @p c. If the character is not displayed, the block is changed. * * @param c the character to highlight */ void setCurrentChar(const QChar &c); /** * Highlights the character with the specified @p codePoint. If the character is * outside the Basic Multilingual Plane (BMP), then you must enable support * for all planes for this to work. * * @param codePoint the Unicode code point of the character to highlight * * @sa allPlanesEnabled * @since 5.25 */ void setCurrentCodePoint(uint codePoint); /** * Sets the font which is displayed to @p font * * @param font the display font for the widget */ void setCurrentFont(const QFont &font); Q_SIGNALS: /** * A new font is selected or the font size changed. * * @param font the new font */ void currentFontChanged(const QFont &font); /** * The current character is changed. * * @param c the new character */ void currentCharChanged(const QChar &c); /** * The current character is changed. * * @param codePoint the Unicode code point of the new character * @since 5.25 */ void currentCodePointChanged(uint codePoint); /** * The currently displayed characters are changed (search results or block). */ void displayedCharsChanged(); /** * A character is selected to be inserted somewhere. * * @param c the selected character */ void charSelected(const QChar &c); /** * A character is selected to be inserted somewhere. * * @param codePoint the Unicode code point of the selected character * @since 5.25 */ void codePointSelected(uint codePoint); private: Q_PRIVATE_SLOT(d, void _k_back()) Q_PRIVATE_SLOT(d, void _k_forward()) Q_PRIVATE_SLOT(d, void _k_fontSelected()) Q_PRIVATE_SLOT(d, void _k_charSelected(uint c)) Q_PRIVATE_SLOT(d, void _k_updateCurrentChar(uint c)) Q_PRIVATE_SLOT(d, void _k_slotUpdateUnicode(uint c)) Q_PRIVATE_SLOT(d, void _k_sectionSelected(int index)) Q_PRIVATE_SLOT(d, void _k_blockSelected(int index)) Q_PRIVATE_SLOT(d, void _k_searchEditChanged()) Q_PRIVATE_SLOT(d, void _k_search()) Q_PRIVATE_SLOT(d, void _k_linkClicked(QUrl)) class KCharSelectPrivate; KCharSelectPrivate *const d; void initWidget(const Controls, QObject *); }; Q_DECLARE_OPERATORS_FOR_FLAGS(KCharSelect::Controls) #endif diff --git a/src/kcollapsiblegroupbox.cpp b/src/kcollapsiblegroupbox.cpp index 0511368..5ee57a8 100644 --- a/src/kcollapsiblegroupbox.cpp +++ b/src/kcollapsiblegroupbox.cpp @@ -1,369 +1,367 @@ /* * This file is part of the KDE project * Copyright (C) 2015 David Edmundson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kcollapsiblegroupbox.h" #include #include #include #include #include -#include -#include #include #include class KCollapsibleGroupBoxPrivate { public: KCollapsibleGroupBoxPrivate(KCollapsibleGroupBox *q); void updateChildrenFocus(bool expanded); void recalculateHeaderSize(); QSize contentSize() const; QSize contentMinimumSize() const; KCollapsibleGroupBox *q; QTimeLine *animation; QString title; bool isExpanded; bool headerContainsMouse; QSize headerSize; int shortcutId; QMap focusMap; // Used to restore focus policy of widgets. }; KCollapsibleGroupBoxPrivate::KCollapsibleGroupBoxPrivate(KCollapsibleGroupBox* q): q(q), isExpanded(false), headerContainsMouse(false), shortcutId(0) {} KCollapsibleGroupBox::KCollapsibleGroupBox(QWidget* parent): QWidget(parent), d(new KCollapsibleGroupBoxPrivate(this)) { d->recalculateHeaderSize(); d->animation = new QTimeLine(500, this); //duration matches kmessagewidget connect(d->animation, &QTimeLine::valueChanged, this, [this](qreal value) { setFixedHeight((d->contentSize().height() * value) + d->headerSize.height()); }); connect(d->animation, &QTimeLine::stateChanged, this, [this](QTimeLine::State state) { if (state == QTimeLine::NotRunning) { d->updateChildrenFocus(d->isExpanded); } }); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); setFocusPolicy(Qt::TabFocus); setMouseTracking(true); } KCollapsibleGroupBox::~KCollapsibleGroupBox() { if (d->animation->state() == QTimeLine::Running) { d->animation->stop(); } delete d; } void KCollapsibleGroupBox::setTitle(const QString& title) { d->title = title; d->recalculateHeaderSize(); update(); updateGeometry(); if (d->shortcutId) { releaseShortcut(d->shortcutId); } d->shortcutId = grabShortcut(QKeySequence::mnemonic(title)); #ifndef QT_NO_ACCESSIBILITY setAccessibleName(title); #endif emit titleChanged(); } QString KCollapsibleGroupBox::title() const { return d->title; } void KCollapsibleGroupBox::setExpanded(bool expanded) { if (expanded == d->isExpanded) { return; } d->isExpanded = expanded; emit expandedChanged(); d->updateChildrenFocus(expanded); d->animation->setDirection(expanded ? QTimeLine::Forward : QTimeLine::Backward); // QTimeLine::duration() must be > 0 const int duration = qMax(1, style()->styleHint(QStyle::SH_Widget_Animation_Duration)); d->animation->setDuration(duration); d->animation->start(); //when going from collapsed to expanded changing the child visibility calls an updateGeometry //which calls sizeHint with expanded true before the first frame of the animation kicks in //trigger an effective frame 0 if (expanded) { setFixedHeight(d->headerSize.height()); } } bool KCollapsibleGroupBox::isExpanded() const { return d->isExpanded; } void KCollapsibleGroupBox::collapse() { setExpanded(false); } void KCollapsibleGroupBox::expand() { setExpanded(true); } void KCollapsibleGroupBox::toggle() { setExpanded(!d->isExpanded); } void KCollapsibleGroupBox::paintEvent(QPaintEvent *event) { QPainter p(this); QStyleOptionButton baseOption; baseOption.initFrom(this); baseOption.rect = QRect(0, 0, width(), d->headerSize.height()); baseOption.text = d->title; if (d->headerContainsMouse) { baseOption.state |= QStyle::State_MouseOver; } QStyle::PrimitiveElement element; if (d->isExpanded) { element = QStyle::PE_IndicatorArrowDown; } else { element = isLeftToRight() ? QStyle::PE_IndicatorArrowRight : QStyle::PE_IndicatorArrowLeft; } QStyleOptionButton indicatorOption = baseOption; indicatorOption.rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &indicatorOption, this); style()->drawPrimitive(element, &indicatorOption, &p, this); QStyleOptionButton labelOption = baseOption; labelOption.rect = style()->subElementRect(QStyle::SE_CheckBoxContents, &labelOption, this); style()->drawControl(QStyle::CE_CheckBoxLabel, &labelOption, &p, this); Q_UNUSED(event) } QSize KCollapsibleGroupBox::sizeHint() const { if (d->isExpanded) { return d->contentSize() + QSize(0, d->headerSize.height()); } else { return QSize(d->contentSize().width(), d->headerSize.height()); } } QSize KCollapsibleGroupBox::minimumSizeHint() const { int minimumWidth = qMax(d->contentSize().width(), d->headerSize.width()); return QSize(minimumWidth, d->headerSize.height()); } bool KCollapsibleGroupBox::event(QEvent *event) { switch (event->type()) { case QEvent::StyleChange: /*fall through*/ case QEvent::FontChange: d->recalculateHeaderSize(); break; case QEvent::Shortcut: { QShortcutEvent *se = static_cast(event); if(d->shortcutId == se->shortcutId()) { toggle(); return true; } break; } case QEvent::ChildAdded: { QChildEvent *ce = static_cast(event); if (ce->child()->isWidgetType()) { auto widget = static_cast(ce->child()); // Needs to be called asynchronously because at this point the widget is likely a "real" QWidget, // i.e. the QWidget base class whose constructor sets the focus policy to NoPolicy. // But the constructor of the child class (not yet called) could set a different focus policy later. QMetaObject::invokeMethod(this, "overrideFocusPolicyOf", Qt::QueuedConnection, Q_ARG(QWidget*, widget)); } break; } case QEvent::LayoutRequest: if (d->animation->state() == QTimeLine::NotRunning) { setFixedHeight(sizeHint().height()); } break; default: break; } return QWidget::event(event); } void KCollapsibleGroupBox::mousePressEvent(QMouseEvent *event) { const QRect headerRect(0, 0, width(), d->headerSize.height()); if (headerRect.contains(event->pos())) { toggle(); } event->setAccepted(true); } //if mouse has changed whether it is in the top bar or not refresh to change arrow icon void KCollapsibleGroupBox::mouseMoveEvent(QMouseEvent *event) { const QRect headerRect(0, 0, width(), d->headerSize.height()); bool headerContainsMouse = headerRect.contains(event->pos()); if (headerContainsMouse != d->headerContainsMouse) { d->headerContainsMouse = headerContainsMouse; update(); } QWidget::mouseMoveEvent(event); } void KCollapsibleGroupBox::leaveEvent(QEvent *event) { d->headerContainsMouse = false; update(); QWidget::leaveEvent(event); } void KCollapsibleGroupBox::keyPressEvent(QKeyEvent *event) { //event might have just propagated up from a child, if so we don't want to react to it if (!hasFocus()) { return; } const int key = event->key(); if (key == Qt::Key_Space || key == Qt::Key_Enter || key == Qt::Key_Return) { toggle(); event->setAccepted(true); } } void KCollapsibleGroupBox::resizeEvent(QResizeEvent *event) { int top, left, right, bottom; getContentsMargins(&left, &top, &right, &bottom); if (layout()) { //we don't want the layout trying to fit the current frame of the animation so always set it to the target height layout()->setGeometry(QRect(left, top, width() - left - right, layout()->sizeHint().height())); } Q_UNUSED(bottom) QWidget::resizeEvent(event); } void KCollapsibleGroupBox::overrideFocusPolicyOf(QWidget *widget) { // https://bugs.kde.org/show_bug.cgi?id=396450 // A label with word-wrapping enabled will break positioning of the groupbox in the layout. // The cause seems to be the setFocusPolicy() call below, but it's not clear why. // Until a proper fix is found, as workaround we toggle twice the groupbox which fixes the issue. if (auto label = qobject_cast(widget)) { if (label->wordWrap()) { toggle(); toggle(); } } d->focusMap.insert(widget, widget->focusPolicy()); if (!isExpanded()) { // Prevent tab focus if not expanded. widget->setFocusPolicy(Qt::NoFocus); } } void KCollapsibleGroupBoxPrivate::recalculateHeaderSize() { QStyleOption option; option.initFrom(q); QSize textSize = q->style()->itemTextRect(option.fontMetrics, QRect(), Qt::TextShowMnemonic, false, title).size(); headerSize = q->style()->sizeFromContents(QStyle::CT_CheckBox, &option, textSize, q); q->setContentsMargins(q->style()->pixelMetric(QStyle::PM_IndicatorWidth), headerSize.height(), 0, 0); } void KCollapsibleGroupBoxPrivate::updateChildrenFocus(bool expanded) { foreach (QObject *child, q->children()) { QWidget *widget = qobject_cast(child); if (!widget) { continue; } // Restore old focus policy if expanded, remove from focus chain otherwise. if (expanded) { widget->setFocusPolicy(focusMap.value(widget)); } else { widget->setFocusPolicy(Qt::NoFocus); } } } QSize KCollapsibleGroupBoxPrivate::contentSize() const { if (q->layout()) { const QMargins margins = q->contentsMargins(); const QSize marginSize(margins.left() + margins.right(), margins.top() + margins.bottom()); return q->layout()->sizeHint() + marginSize; } return QSize(0,0); } QSize KCollapsibleGroupBoxPrivate::contentMinimumSize() const { if (q->layout()) { const QMargins margins = q->contentsMargins(); const QSize marginSize(margins.left() + margins.right(), margins.top() + margins.bottom()); return q->layout()->minimumSize() + marginSize; } return QSize(0,0); } diff --git a/src/kcolumnresizer.cpp b/src/kcolumnresizer.cpp index 80f0b4a..9ba0ec7 100644 --- a/src/kcolumnresizer.cpp +++ b/src/kcolumnresizer.cpp @@ -1,250 +1,249 @@ /* This file is part of the KDE frameworks * * Copyright (c) 2014 Aurélien Gâteau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include #include "loggingcategory.h" -#include #include #include #include #include #include #include class FormLayoutWidgetItem : public QWidgetItem { public: FormLayoutWidgetItem(QWidget *widget, QFormLayout *formLayout, QFormLayout::ItemRole itemRole) : QWidgetItem(widget) , m_formLayout(formLayout) , m_width(-1) , m_itemRole(itemRole) {} void setWidth(int width) { if (width != m_width) { m_width = width; invalidate(); } } QFormLayout *formLayout() const { return m_formLayout; } QSize sizeHint() const override { QSize size = QWidgetItem::sizeHint(); if (m_width != -1) { size.setWidth(m_width); } return size; } QSize minimumSize() const override { QSize size = QWidgetItem::minimumSize(); if (m_width != -1) { size.setWidth(m_width); } return size; } QSize maximumSize() const override { QSize size = QWidgetItem::maximumSize(); if (m_width != -1) { size.setWidth(m_width); } return size; } void setGeometry(const QRect &_rect) override { QRect rect = _rect; int width = widget()->sizeHint().width(); if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) { rect.setLeft(rect.right() - width); } QWidgetItem::setGeometry(rect); } private: QFormLayout *m_formLayout; int m_width; QFormLayout::ItemRole m_itemRole; }; struct GridColumnInfo { GridColumnInfo(QGridLayout *layout_, int column_) : layout(layout_) , column(column_) {} QGridLayout *layout; int column; }; class KColumnResizerPrivate { public: KColumnResizerPrivate(KColumnResizer *q_ptr) : q(q_ptr) , m_updateTimer(new QTimer(q)) { m_updateTimer->setSingleShot(true); m_updateTimer->setInterval(0); QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth())); } void scheduleWidthUpdate() { m_updateTimer->start(); } void updateWidth() { int width = 0; Q_FOREACH(QWidget *widget, m_widgets) { width = qMax(widget->sizeHint().width(), width); } Q_FOREACH(FormLayoutWidgetItem *item, m_formWidgetItemList) { item->setWidth(width); item->formLayout()->update(); } Q_FOREACH(const GridColumnInfo &info, m_gridColumnInfoList) { info.layout->setColumnMinimumWidth(info.column, width); } } void addWidgetsFromGridLayout(QGridLayout *layout, int column) { for (int row = 0; row < layout->rowCount(); ++row) { QLayoutItem *item = layout->itemAtPosition(row, column); if (!item) { continue; } QWidget *widget = item->widget(); if (!widget) { continue; } q->addWidget(widget); } m_gridColumnInfoList << GridColumnInfo(layout, column); } void addWidgetsFromFormLayout(QFormLayout *layout, QFormLayout::ItemRole role) { for (int row = 0; row < layout->rowCount(); ++row) { QLayoutItem *item = layout->itemAt(row, role); if (!item) { continue; } QWidget *widget = item->widget(); if (!widget) { continue; } // Replace the QWidgetItem with our own layout->removeItem(item); delete item; FormLayoutWidgetItem *newItem = new FormLayoutWidgetItem(widget, layout, role); layout->setItem(row, role, newItem); m_formWidgetItemList << newItem; q->addWidget(widget); } } KColumnResizer *q; QTimer *m_updateTimer; QSet m_widgets; QList m_formWidgetItemList; QList m_gridColumnInfoList; }; KColumnResizer::KColumnResizer(QObject *parent) : QObject(parent) , d(new KColumnResizerPrivate(this)) {} KColumnResizer::~KColumnResizer() { delete d; } void KColumnResizer::addWidget(QWidget *widget) { if (d->m_widgets.contains(widget)) { return; } d->m_widgets.insert(widget); widget->installEventFilter(this); d->scheduleWidthUpdate(); } void KColumnResizer::removeWidget(QWidget *widget) { if (!d->m_widgets.remove(widget)) { return; } widget->removeEventFilter(this); d->scheduleWidthUpdate(); } bool KColumnResizer::eventFilter(QObject *, QEvent *event) { if (event->type() == QEvent::Resize) { d->scheduleWidthUpdate(); } return false; } void KColumnResizer::addWidgetsFromLayout(QLayout *layout, int column) { Q_ASSERT(column >= 0); if (column < 0) { qCWarning(KWidgetsAddonsLog) << "column must be >= 0"; return; } QGridLayout *gridLayout = qobject_cast(layout); if (gridLayout) { d->addWidgetsFromGridLayout(gridLayout, column); return; } QFormLayout *formLayout = qobject_cast(layout); if (formLayout) { Q_ASSERT(column <= QFormLayout::SpanningRole); if (column > QFormLayout::SpanningRole) { qCWarning(KWidgetsAddonsLog) << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout"; return; } QFormLayout::ItemRole role = static_cast(column); d->addWidgetsFromFormLayout(formLayout, role); } else { qCWarning(KWidgetsAddonsLog) << "Don't know how to handle layout" << layout; Q_ASSERT(0); } } #include // vi: ts=4 sw=4 et diff --git a/src/kcursor.cpp b/src/kcursor.cpp index 41fea34..a52de6c 100644 --- a/src/kcursor.cpp +++ b/src/kcursor.cpp @@ -1,274 +1,273 @@ /* This file is part of the KDE libraries Copyright (C) 1998 Kurt Granroth (granroth@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcursor.h" #include "kcursor_p.h" #include #include #include #include #include -#include void KCursor::setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter) { KCursorPrivate::self()->setAutoHideCursor(w, enable, customEventFilter); } void KCursor::autoHideEventFilter(QObject *o, QEvent *e) { KCursorPrivate::self()->eventFilter(o, e); } void KCursor::setHideCursorDelay(int ms) { KCursorPrivate::self()->hideCursorDelay = ms; } int KCursor::hideCursorDelay() { return KCursorPrivate::self()->hideCursorDelay; } // ************************************************************************** KCursorPrivateAutoHideEventFilter::KCursorPrivateAutoHideEventFilter(QWidget *widget) : m_widget(widget) , m_wasMouseTracking(m_widget->hasMouseTracking()) , m_isCursorHidden(false) , m_isOwnCursor(false) { mouseWidget()->setMouseTracking(true); connect(&m_autoHideTimer, &QTimer::timeout, this, &KCursorPrivateAutoHideEventFilter::hideCursor); } KCursorPrivateAutoHideEventFilter::~KCursorPrivateAutoHideEventFilter() { if (m_widget != nullptr) { mouseWidget()->setMouseTracking(m_wasMouseTracking); } } void KCursorPrivateAutoHideEventFilter::resetWidget() { m_widget = nullptr; } void KCursorPrivateAutoHideEventFilter::hideCursor() { m_autoHideTimer.stop(); if (m_isCursorHidden) { return; } m_isCursorHidden = true; QWidget *w = mouseWidget(); m_isOwnCursor = w->testAttribute(Qt::WA_SetCursor); if (m_isOwnCursor) { m_oldCursor = w->cursor(); } w->setCursor(QCursor(Qt::BlankCursor)); } void KCursorPrivateAutoHideEventFilter::unhideCursor() { m_autoHideTimer.stop(); if (!m_isCursorHidden) { return; } m_isCursorHidden = false; QWidget *w = mouseWidget(); if (w->cursor().shape() != Qt::BlankCursor) { // someone messed with the cursor already return; } if (m_isOwnCursor) { w->setCursor(m_oldCursor); } else { w->unsetCursor(); } } // The widget which gets mouse events, and that shows the cursor // (that is the viewport, for a QAbstractScrollArea) QWidget *KCursorPrivateAutoHideEventFilter::mouseWidget() const { QWidget *w = m_widget; // Is w a QAbstractScrollArea ? Call setCursor on the viewport in that case. QAbstractScrollArea *sv = qobject_cast(w); if (sv) { w = sv->viewport(); } return w; } bool KCursorPrivateAutoHideEventFilter::eventFilter(QObject *o, QEvent *e) { Q_UNUSED(o); // o is m_widget or its viewport //Q_ASSERT( o == m_widget ); switch (e->type()) { case QEvent::Leave: case QEvent::FocusOut: case QEvent::WindowDeactivate: unhideCursor(); break; case QEvent::KeyPress: case QEvent::ShortcutOverride: hideCursor(); break; case QEvent::Enter: case QEvent::FocusIn: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::Show: case QEvent::Hide: case QEvent::Wheel: unhideCursor(); if (m_widget->hasFocus()) { m_autoHideTimer.setSingleShot(true); m_autoHideTimer.start(KCursorPrivate::self()->hideCursorDelay); } break; default: break; } return false; } KCursorPrivate *KCursorPrivate::s_self = nullptr; KCursorPrivate *KCursorPrivate::self() { if (!s_self) { s_self = new KCursorPrivate; } // WABA: Don't delete KCursorPrivate, it serves no real purpose. // Even worse it causes crashes because it seems to get deleted // during ~QApplication and ~QApplication doesn't seem to like it // when we delete a QCursor. No idea if that is a bug itself. return s_self; } KCursorPrivate::KCursorPrivate() { hideCursorDelay = 5000; // 5s default value enabled = true; } KCursorPrivate::~KCursorPrivate() { } void KCursorPrivate::setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter) { if (!w || !enabled) { return; } QWidget *viewport = nullptr; QAbstractScrollArea *sv = qobject_cast(w); if (sv) { viewport = sv->viewport(); } if (enable) { if (m_eventFilters.contains(w)) { return; } KCursorPrivateAutoHideEventFilter *filter = new KCursorPrivateAutoHideEventFilter(w); m_eventFilters.insert(w, filter); if (viewport) { m_eventFilters.insert(viewport, filter); connect(viewport, &QObject::destroyed, this, &KCursorPrivate::slotViewportDestroyed); } if (!customEventFilter) { w->installEventFilter(filter); // for key events if (viewport) { viewport->installEventFilter(filter); // for mouse events } } connect(w, &QObject::destroyed, this, &KCursorPrivate::slotWidgetDestroyed); } else { KCursorPrivateAutoHideEventFilter *filter = m_eventFilters.take(w); if (filter == nullptr) { return; } w->removeEventFilter(filter); if (viewport) { m_eventFilters.remove(viewport); disconnect(viewport, &QObject::destroyed, this, &KCursorPrivate::slotViewportDestroyed); viewport->removeEventFilter(filter); } delete filter; disconnect(w, &QObject::destroyed, this, &KCursorPrivate::slotWidgetDestroyed); } } bool KCursorPrivate::eventFilter(QObject *o, QEvent *e) { if (!enabled || e->type() == QEvent::ChildAdded) { return false; } KCursorPrivateAutoHideEventFilter *filter = m_eventFilters.value(o); Q_ASSERT(filter != nullptr); if (filter == nullptr) { return false; } return filter->eventFilter(o, e); } void KCursorPrivate::slotViewportDestroyed(QObject *o) { m_eventFilters.remove(o); } void KCursorPrivate::slotWidgetDestroyed(QObject *o) { KCursorPrivateAutoHideEventFilter *filter = m_eventFilters.take(o); Q_ASSERT(filter != nullptr); filter->resetWidget(); // so that dtor doesn't access it delete filter; } #include "moc_kcursor_p.cpp" diff --git a/src/kdatecombobox.cpp b/src/kdatecombobox.cpp index b09c0ab..2f6fc77 100644 --- a/src/kdatecombobox.cpp +++ b/src/kdatecombobox.cpp @@ -1,606 +1,607 @@ /* Copyright 2011 John Layt This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kdatecombobox.h" #include #include #include #include #include #include #include #include +#include #include "kdatepicker.h" #include "kmessagebox.h" class KDateComboBoxPrivate { public: KDateComboBoxPrivate(KDateComboBox *q); virtual ~KDateComboBoxPrivate(); // TODO: Find a way to get that from QLocale #if 0 QDate defaultMinDate(); QDate defaultMaxDate(); #endif QString dateFormat(QLocale::FormatType format); QString formatDate(const QDate &date); void initDateWidget(); void addMenuAction(const QString &text, const QDate &date); void enableMenuDates(); void updateDateWidget(); void setDateRange(const QDate &minDate, const QDate &maxDate, const QString &minWarnMsg, const QString &maxWarnMsg); bool isInDateRange(const QDate &date) const; void clickDate(); void selectDate(QAction *action); void editDate(const QString &text); void enterDate(const QDate &date); void parseDate(); void warnDate(); KDateComboBox *const q; QMenu *m_dateMenu; QVector m_actions; KDatePicker *m_datePicker; QWidgetAction *m_datePickerAction; QDate m_date; KDateComboBox::Options m_options; QDate m_minDate; QDate m_maxDate; QString m_minWarnMsg; QString m_maxWarnMsg; bool m_warningShown; bool m_edited; // and dateChanged not yet emitted QLocale::FormatType m_displayFormat; QMap m_dateMap; }; KDateComboBoxPrivate::KDateComboBoxPrivate(KDateComboBox *q) : q(q), m_dateMenu(new QMenu(q)), m_datePicker(new KDatePicker(q)), m_datePickerAction(new QWidgetAction(q)), m_warningShown(false), m_edited(false), m_displayFormat(QLocale::ShortFormat) { m_options = KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker | KDateComboBox::DateKeywords; m_date = QDate::currentDate(); //m_minDate = defaultMinDate(); //m_maxDate = defaultMaxDate(); m_datePicker->setCloseButton(false); m_datePickerAction->setObjectName(QStringLiteral("DatePicker")); m_datePickerAction->setDefaultWidget(m_datePicker); } KDateComboBoxPrivate::~KDateComboBoxPrivate() { } #if 0 QDate KDateComboBoxPrivate::defaultMinDate() { return m_date.calendar()->earliestValidDate(); } QDate KDateComboBoxPrivate::defaultMaxDate() { return m_date.calendar()->latestValidDate(); } #endif QString KDateComboBoxPrivate::dateFormat(QLocale::FormatType format) { // Clearly a workaround for QLocale using "yy" way too often for years // and so you get no way to distinguish between 1913 and 2013 anymore... // bummer. QString res = q->locale().dateFormat(format); res.replace(QStringLiteral("yy"), QStringLiteral("yyyy")); res.replace(QStringLiteral("yyyyyyyy"), QStringLiteral("yyyy")); return res; } QString KDateComboBoxPrivate::formatDate(const QDate &date) { return q->locale().toString(date, dateFormat(m_displayFormat)); } void KDateComboBoxPrivate::initDateWidget() { q->blockSignals(true); q->clear(); // If EditTime then set the line edit q->lineEdit()->setReadOnly((m_options & KDateComboBox::EditDate) != KDateComboBox::EditDate); // If SelectDate then make list items visible if ((m_options & KDateComboBox::SelectDate) == KDateComboBox::SelectDate || (m_options & KDateComboBox::DatePicker) == KDateComboBox::DatePicker || (m_options & KDateComboBox::DatePicker) == KDateComboBox::DateKeywords) { q->setMaxVisibleItems(1); } else { q->setMaxVisibleItems(0); } q->setSizeAdjustPolicy(QComboBox::AdjustToContents); q->addItem(formatDate(m_date)); q->setCurrentIndex(0); q->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); q->blockSignals(false); m_dateMenu->clear(); m_actions.clear(); if ((m_options & KDateComboBox::SelectDate) == KDateComboBox::SelectDate) { if ((m_options & KDateComboBox::DatePicker) == KDateComboBox::DatePicker) { m_dateMenu->addAction(m_datePickerAction); m_dateMenu->addSeparator(); } if ((m_options & KDateComboBox::DateKeywords) == KDateComboBox::DateKeywords) { if (m_dateMap.isEmpty()) { addMenuAction(KDateComboBox::tr("Next Year", "@option next year"), m_date.addYears(1)); addMenuAction(KDateComboBox::tr("Next Month", "@option next month"), m_date.addMonths(1)); addMenuAction(KDateComboBox::tr("Next Week", "@option next week"), m_date.addDays(7)); addMenuAction(KDateComboBox::tr("Tomorrow", "@option tomorrow"), m_date.addDays(1)); addMenuAction(KDateComboBox::tr("Today", "@option today"), m_date); addMenuAction(KDateComboBox::tr("Yesterday", "@option yesterday"), m_date.addDays(-1)); addMenuAction(KDateComboBox::tr("Last Week", "@option last week"), m_date.addDays(-7)); addMenuAction(KDateComboBox::tr("Last Month", "@option last month"), m_date.addMonths(-1)); addMenuAction(KDateComboBox::tr("Last Year", "@option last year"), m_date.addYears(-1)); m_dateMenu->addSeparator(); addMenuAction(KDateComboBox::tr("No Date", "@option do not specify a date"), QDate()); } else { QMapIterator i(m_dateMap); while (i.hasNext()) { i.next(); if (i.value().isEmpty()) { addMenuAction(formatDate(i.key()), i.key()); } else if (i.value().toLower() == QLatin1String("separator")) { m_dateMenu->addSeparator(); } else { addMenuAction(i.value(), i.key()); } } } enableMenuDates(); } } } void KDateComboBoxPrivate::addMenuAction(const QString &text, const QDate &date) { QAction *action = new QAction(m_dateMenu); action->setText(text); action->setData(date); m_dateMenu->addAction(action); m_actions << action; } void KDateComboBoxPrivate::enableMenuDates() { // Hide menu dates if they are outside the date range for (int i = 0; i < m_actions.count(); ++i) { QDate date = m_actions[i]->data().toDate(); m_actions[i]->setVisible(!date.isValid() || isInDateRange(date)); } } void KDateComboBoxPrivate::updateDateWidget() { q->blockSignals(true); m_datePicker->blockSignals(true); m_datePicker->setDate(m_date); int pos = q->lineEdit()->cursorPosition(); q->setItemText(0, formatDate(m_date)); q->lineEdit()->setText(formatDate(m_date)); q->lineEdit()->setCursorPosition(pos); m_datePicker->blockSignals(false); q->blockSignals(false); } void KDateComboBoxPrivate::setDateRange(const QDate &minDate, const QDate &maxDate, const QString &minWarnMsg, const QString &maxWarnMsg) { if (minDate.isValid() && maxDate.isValid() && minDate > maxDate) { return; } if (minDate != m_minDate || maxDate != m_maxDate || minWarnMsg != m_minWarnMsg || maxWarnMsg != m_maxWarnMsg) { m_minDate = minDate; m_maxDate = maxDate; m_minWarnMsg = minWarnMsg; m_maxWarnMsg = maxWarnMsg; } enableMenuDates(); } bool KDateComboBoxPrivate::isInDateRange(const QDate &date) const { return date.isValid() && (!m_minDate.isValid() || date >= m_minDate) && (!m_maxDate.isValid() || date <= m_maxDate); } void KDateComboBoxPrivate::selectDate(QAction *action) { if (action->objectName() != QLatin1String("DatePicker")) { QDate date = action->data().toDate(); if (isInDateRange(date)) { enterDate(date); } } } void KDateComboBoxPrivate::clickDate() { QDate date = m_datePicker->date(); if (isInDateRange(date)) { enterDate(date); } } void KDateComboBoxPrivate::editDate(const QString &text) { m_warningShown = false; m_date = q->locale().toDate(text, dateFormat(m_displayFormat)); m_edited = true; emit q->dateEdited(m_date); } void KDateComboBoxPrivate::parseDate() { m_date = q->locale().toDate(q->lineEdit()->text(), dateFormat(m_displayFormat)); } void KDateComboBoxPrivate::enterDate(const QDate &date) { q->setDate(date); // Re-add the combo box item in order to retain the correct widget width q->blockSignals(true); q->clear(); q->setSizeAdjustPolicy(QComboBox::AdjustToContents); q->addItem(formatDate(m_date)); q->setCurrentIndex(0); q->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); q->blockSignals(false); m_dateMenu->hide(); warnDate(); emit q->dateEntered(m_date); } void KDateComboBoxPrivate::warnDate() { if (!m_warningShown && !q->isValid() && (m_options & KDateComboBox::WarnOnInvalid) == KDateComboBox::WarnOnInvalid) { QString warnMsg; if (!m_date.isValid()) { warnMsg = KDateComboBox::tr("The date you entered is invalid", "@info"); } else if (m_minDate.isValid() && m_date < m_minDate) { if (m_minWarnMsg.isEmpty()) { warnMsg = KDateComboBox::tr("Date cannot be earlier than %1", "@info").arg(formatDate(m_minDate)); } else { warnMsg = m_minWarnMsg; warnMsg.replace(QStringLiteral("%1"), formatDate(m_minDate)); } } else if (m_maxDate.isValid() && m_date > m_maxDate) { if (m_maxWarnMsg.isEmpty()) { warnMsg = KDateComboBox::tr("Date cannot be later than %1", "@info").arg(formatDate(m_maxDate)); } else { warnMsg = m_maxWarnMsg; warnMsg.replace(QStringLiteral("%1"), formatDate(m_maxDate)); } } m_warningShown = true; KMessageBox::sorry(q, warnMsg); } } KDateComboBox::KDateComboBox(QWidget *parent) : QComboBox(parent), d(new KDateComboBoxPrivate(this)) { setEditable(true); setMaxVisibleItems(1); setInsertPolicy(QComboBox::NoInsert); d->m_datePicker->installEventFilter(this); d->initDateWidget(); d->updateDateWidget(); connect(d->m_dateMenu, &QMenu::triggered, this, [this](QAction *action) { d->selectDate(action); }); connect(this, &QComboBox::editTextChanged, this, [this](const QString &text) { d->editDate(text); }); connect(lineEdit(), &QLineEdit::returnPressed, this, [this]() { if (d->m_edited) { d->enterDate(date()); emit dateChanged(date()); } }); connect(d->m_datePicker, &KDatePicker::dateEntered, this, [this](const QDate &date) { d->enterDate(date); }); connect(d->m_datePicker, &KDatePicker::tableClicked, this, [this]() { d->clickDate(); }); } KDateComboBox::~KDateComboBox() { delete d; } QDate KDateComboBox::date() const { d->parseDate(); return d->m_date; } void KDateComboBox::setDate(const QDate &date) { if (date == d->m_date) { return; } d->m_edited = false; assignDate(date); d->updateDateWidget(); emit dateChanged(d->m_date); } void KDateComboBox::assignDate(const QDate &date) { d->m_date = date; } bool KDateComboBox::isValid() const { d->parseDate(); return d->isInDateRange(d->m_date); } bool KDateComboBox::isNull() const { return lineEdit()->text().isEmpty(); } KDateComboBox::Options KDateComboBox::options() const { return d->m_options; } void KDateComboBox::setOptions(Options options) { if (options != d->m_options) { d->m_options = options; d->initDateWidget(); d->updateDateWidget(); } } QDate KDateComboBox::minimumDate() const { return d->m_minDate; } void KDateComboBox::setMinimumDate(const QDate &minDate, const QString &minWarnMsg) { if (minDate.isValid()) { d->setDateRange(minDate, d->m_maxDate, minWarnMsg, d->m_maxWarnMsg); } } void KDateComboBox::resetMinimumDate() { d->setDateRange(QDate(), d->m_maxDate, QString(), d->m_maxWarnMsg); } QDate KDateComboBox::maximumDate() const { return d->m_maxDate; } void KDateComboBox::setMaximumDate(const QDate &maxDate, const QString &maxWarnMsg) { if (maxDate.isValid()) { d->setDateRange(d->m_minDate, maxDate, d->m_minWarnMsg, maxWarnMsg); } } void KDateComboBox::resetMaximumDate() { d->setDateRange(d->m_minDate, QDate(), d->m_minWarnMsg, QString()); } void KDateComboBox::setDateRange(const QDate &minDate, const QDate &maxDate, const QString &minWarnMsg, const QString &maxWarnMsg) { if (minDate.isValid() && maxDate.isValid()) { d->setDateRange(minDate, maxDate, minWarnMsg, maxWarnMsg); } } void KDateComboBox::resetDateRange() { d->setDateRange(QDate(), QDate(), QString(), QString()); } QLocale::FormatType KDateComboBox::displayFormat() const { return d->m_displayFormat; } void KDateComboBox::setDisplayFormat(QLocale::FormatType format) { if (format != d->m_displayFormat) { d->m_displayFormat = format; d->initDateWidget(); d->updateDateWidget(); } } QMap KDateComboBox::dateMap() const { return d->m_dateMap; } void KDateComboBox::setDateMap(QMap dateMap) { if (dateMap != d->m_dateMap) { d->m_dateMap.clear(); d->m_dateMap = dateMap; d->initDateWidget(); } } bool KDateComboBox::eventFilter(QObject *object, QEvent *event) { return QComboBox::eventFilter(object, event); } void KDateComboBox::keyPressEvent(QKeyEvent *keyEvent) { QDate temp; switch (keyEvent->key()) { case Qt::Key_Down: temp = d->m_date.addDays(-1); break; case Qt::Key_Up: temp = d->m_date.addDays(1); break; case Qt::Key_PageDown: temp = d->m_date.addMonths(-1); break; case Qt::Key_PageUp: temp = d->m_date.addMonths(1); break; default: QComboBox::keyPressEvent(keyEvent); return; } if (d->isInDateRange(temp)) { d->enterDate(temp); } } void KDateComboBox::focusOutEvent(QFocusEvent *event) { d->parseDate(); d->warnDate(); if (d->m_edited) { d->m_edited = false; emit dateChanged(d->m_date); } QComboBox::focusOutEvent(event); } void KDateComboBox::showPopup() { if (!isEditable() || !d->m_dateMenu || (d->m_options & KDateComboBox::SelectDate) != KDateComboBox::SelectDate) { return; } d->m_datePicker->blockSignals(true); d->m_datePicker->setDate(d->m_date); d->m_datePicker->blockSignals(false); const QRect desk = QApplication::desktop()->screenGeometry(this); QPoint popupPoint = mapToGlobal(QPoint(0, 0)); const int dateFrameHeight = d->m_dateMenu->sizeHint().height(); if (popupPoint.y() + height() + dateFrameHeight > desk.bottom()) { popupPoint.setY(popupPoint.y() - dateFrameHeight); } else { popupPoint.setY(popupPoint.y() + height()); } const int dateFrameWidth = d->m_dateMenu->sizeHint().width(); if (popupPoint.x() + dateFrameWidth > desk.right()) { popupPoint.setX(desk.right() - dateFrameWidth); } if (popupPoint.x() < desk.left()) { popupPoint.setX(desk.left()); } if (popupPoint.y() < desk.top()) { popupPoint.setY(desk.top()); } d->m_dateMenu->popup(popupPoint); } void KDateComboBox::hidePopup() { QComboBox::hidePopup(); } void KDateComboBox::mousePressEvent(QMouseEvent *event) { QComboBox::mousePressEvent(event); } void KDateComboBox::wheelEvent(QWheelEvent *event) { QDate temp; if (event->delta() < 0) { temp = d->m_date.addDays(-1); } else { temp = d->m_date.addDays(1); } if (d->isInDateRange(temp)) { d->enterDate(temp); } } void KDateComboBox::focusInEvent(QFocusEvent *event) { QComboBox::focusInEvent(event); } void KDateComboBox::resizeEvent(QResizeEvent *event) { QComboBox::resizeEvent(event); } #include "moc_kdatecombobox.cpp" diff --git a/src/kdatepicker.cpp b/src/kdatepicker.cpp index 541e8de..21fd107 100644 --- a/src/kdatepicker.cpp +++ b/src/kdatepicker.cpp @@ -1,659 +1,657 @@ /* -*- C++ -*- This file is part of the KDE libraries Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) (C) 1998-2001 Mirko Boehm (mirko@kde.org) (C) 2007 John Layt This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kdatepicker.h" #include "kdatepicker_p.h" #include "kdatetable_p.h" #include #include #include #include #include -#include #include #include -#include #include #include -#include +#include #include "moc_kdatepicker.cpp" #include "moc_kdatepicker_p.cpp" class DatePickerValidator : public QValidator { Q_OBJECT public: DatePickerValidator(KDatePicker *parent) : QValidator(parent), picker(parent) {} State validate(QString &text, int &) const override { QLocale::FormatType formats[] = { QLocale::LongFormat, QLocale::ShortFormat, QLocale::NarrowFormat }; QLocale locale = picker->locale(); for (int i = 0; i < 3; i++) { QDate tmp = locale.toDate(text, formats[i]); if (tmp.isValid()) { return Acceptable; } } return QValidator::Intermediate; } private: KDatePicker *picker; }; // Week numbers are defined by ISO 8601 // See http://www.merlyn.demon.co.uk/weekinfo.htm for details KDatePickerPrivateYearSelector::KDatePickerPrivateYearSelector( const QDate ¤tDate, QWidget *parent) : QLineEdit(parent), val(new QIntValidator(this)), result(0) { oldDate = currentDate; setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); setFrame(false); // TODO: Find a way to get that from QLocale //val->setRange( calendar->year( calendar->earliestValidDate() ), // calendar->year( calendar->latestValidDate() ) ); setValidator(val); connect(this, &QLineEdit::returnPressed, this, &KDatePickerPrivateYearSelector::yearEnteredSlot); } void KDatePickerPrivateYearSelector::yearEnteredSlot() { bool ok; int newYear; // check if entered value is a number newYear = text().toInt(&ok); if (!ok) { QApplication::beep(); return; } // check if new year will lead to a valid date if (QDate(newYear, oldDate.month(), oldDate.day()).isValid()) { result = newYear; emit closeMe(1); } else { QApplication::beep(); } } int KDatePickerPrivateYearSelector::year() { return result; } void KDatePickerPrivateYearSelector::setYear(int year) { setText(QString::number(year)); } class Q_DECL_HIDDEN KDatePicker::KDatePickerPrivate { public: KDatePickerPrivate(KDatePicker *q) : q(q), closeButton(nullptr), selectWeek(nullptr), todayButton(nullptr), navigationLayout(nullptr) { } void fillWeeksCombo(); QDate validDateInYearMonth(int year, int month); /// the date table KDatePicker *q; QToolButton *closeButton; QComboBox *selectWeek; QToolButton *todayButton; QBoxLayout *navigationLayout; /// the year forward button QToolButton *yearForward; /// the year backward button QToolButton *yearBackward; /// the month forward button QToolButton *monthForward; /// the month backward button QToolButton *monthBackward; /// the button for selecting the month directly QToolButton *selectMonth; /// the button for selecting the year directly QToolButton *selectYear; /// the line edit to enter the date directly QLineEdit *line; /// the validator for the line edit: DatePickerValidator *val; /// the date table KDateTable *table; /// the widest month string in pixels: QSize maxMonthRect; /// the font size for the widget int fontsize; }; void KDatePicker::KDatePickerPrivate::fillWeeksCombo() { // every year can have a different number of weeks // it could be that we had 53,1..52 and now 1..53 which is the same number but different // so always fill with new values // We show all week numbers for all weeks between first day of year to last day of year // This of course can be a list like 53,1,2..52 const QDate thisDate = q->date(); const int thisYear = thisDate.year(); QDate day(thisDate.year(), 1, 1); const QDate lastDayOfYear = QDate(thisDate.year() + 1, 1, 1).addDays(-1); selectWeek->clear(); // Starting from the first day in the year, loop through the year a week at a time // adding an entry to the week combo for each week in the year for (; day.isValid() && day <= lastDayOfYear; day = day.addDays(7)) { // Get the ISO week number for the current day and what year that week is in // e.g. 1st day of this year may fall in week 53 of previous year int weekYear = thisYear; const int week = day.weekNumber(&weekYear); QString weekString = tr("Week %1").arg(QString::number(week)); // show that this is a week from a different year if (weekYear != thisYear) { weekString += QLatin1Char('*'); } // when the week is selected, go to the same weekday as the one // that is currently selected in the date table QDate targetDate = day.addDays(thisDate.dayOfWeek() - day.dayOfWeek()); selectWeek->addItem(weekString, targetDate); // make sure that the week of the lastDayOfYear is always inserted: in Chinese calendar // system, this is not always the case if (day < lastDayOfYear && day.daysTo(lastDayOfYear) < 7 && lastDayOfYear.weekNumber() != day.weekNumber()) { day = lastDayOfYear.addDays(-7); } } } QDate KDatePicker::KDatePickerPrivate::validDateInYearMonth(int year, int month) { QDate newDate; // Try to create a valid date in this year and month // First try the first of the month, then try last of month if (QDate(year, month, 1).isValid()) { newDate = QDate(year, month, 1); } else if (QDate(year, month + 1, 1).isValid()) { newDate = QDate(year, month + 1, 1).addDays(-1); } else { newDate = QDate::fromJulianDay(0); } return newDate; } KDatePicker::KDatePicker(QWidget *parent) : QFrame(parent), d(new KDatePickerPrivate(this)) { initWidget(QDate::currentDate()); } KDatePicker::KDatePicker(const QDate &date_, QWidget *parent) : QFrame(parent), d(new KDatePickerPrivate(this)) { initWidget(date_); } void KDatePicker::initWidget(const QDate &date_) { const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); QBoxLayout *topLayout = new QVBoxLayout(this); topLayout->setSpacing(0); topLayout->setContentsMargins(0, 0, 0, 0); d->navigationLayout = new QHBoxLayout(); d->navigationLayout->setSpacing(0); d->navigationLayout->setContentsMargins(0, 0, 0, 0); topLayout->addLayout(d->navigationLayout); d->navigationLayout->addStretch(); d->yearBackward = new QToolButton(this); d->yearBackward->setAutoRaise(true); d->navigationLayout->addWidget(d->yearBackward); d->monthBackward = new QToolButton(this); d->monthBackward ->setAutoRaise(true); d->navigationLayout->addWidget(d->monthBackward); d->navigationLayout->addSpacing(spacingHint); d->selectMonth = new QToolButton(this); d->selectMonth ->setAutoRaise(true); d->navigationLayout->addWidget(d->selectMonth); d->selectYear = new QToolButton(this); d->selectYear->setCheckable(true); d->selectYear->setAutoRaise(true); d->navigationLayout->addWidget(d->selectYear); d->navigationLayout->addSpacing(spacingHint); d->monthForward = new QToolButton(this); d->monthForward ->setAutoRaise(true); d->navigationLayout->addWidget(d->monthForward); d->yearForward = new QToolButton(this); d->yearForward ->setAutoRaise(true); d->navigationLayout->addWidget(d->yearForward); d->navigationLayout->addStretch(); d->line = new QLineEdit(this); d->val = new DatePickerValidator(this); d->table = new KDateTable(this); setFocusProxy(d->table); d->fontsize = QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize(); if (d->fontsize == -1) { d->fontsize = QFontInfo(QFontDatabase::systemFont(QFontDatabase::GeneralFont)).pointSize(); } d->fontsize++; // Make a little bigger d->selectWeek = new QComboBox(this); // read only week selection d->selectWeek->setFocusPolicy(Qt::NoFocus); d->todayButton = new QToolButton(this); d->todayButton->setIcon(QIcon::fromTheme(QStringLiteral("go-jump-today"))); d->yearForward->setToolTip(tr("Next year")); d->yearBackward->setToolTip(tr("Previous year")); d->monthForward->setToolTip(tr("Next month")); d->monthBackward->setToolTip(tr("Previous month")); d->selectWeek->setToolTip(tr("Select a week")); d->selectMonth->setToolTip(tr("Select a month")); d->selectYear->setToolTip(tr("Select a year")); d->todayButton->setToolTip(tr("Select the current day")); // ----- setFontSize(d->fontsize); d->line->setValidator(d->val); d->line->installEventFilter(this); if (QApplication::isRightToLeft()) { d->yearForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left-double"))); d->yearBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right-double"))); d->monthForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left"))); d->monthBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right"))); } else { d->yearForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right-double"))); d->yearBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left-double"))); d->monthForward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right"))); d->monthBackward->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left"))); } connect(d->table, QOverload::of(&KDateTable::dateChanged), this, &KDatePicker::dateChangedSlot); connect(d->table, &KDateTable::tableClicked, this, &KDatePicker::tableClickedSlot); connect(d->monthForward, &QAbstractButton::clicked, this, &KDatePicker::monthForwardClicked); connect(d->monthBackward, &QAbstractButton::clicked, this, &KDatePicker::monthBackwardClicked); connect(d->yearForward, &QAbstractButton::clicked, this, &KDatePicker::yearForwardClicked); connect(d->yearBackward, &QAbstractButton::clicked, this, &KDatePicker::yearBackwardClicked); connect(d->selectWeek, QOverload::of(&QComboBox::activated), this, &KDatePicker::weekSelected); connect(d->todayButton, &QAbstractButton::clicked, this, &KDatePicker::todayButtonClicked); connect(d->selectMonth, &QAbstractButton::clicked, this, &KDatePicker::selectMonthClicked); connect(d->selectYear, &QAbstractButton::toggled, this, &KDatePicker::selectYearClicked); connect(d->line, &QLineEdit::returnPressed, this, &KDatePicker::lineEnterPressed); topLayout->addWidget(d->table); QBoxLayout *bottomLayout = new QHBoxLayout(); bottomLayout->setContentsMargins(0, 0, 0, 0); bottomLayout->setSpacing(0); topLayout->addLayout(bottomLayout); bottomLayout->addWidget(d->todayButton); bottomLayout->addWidget(d->line); bottomLayout->addWidget(d->selectWeek); d->table->setDate(date_); dateChangedSlot(date_); // needed because table emits changed only when newDate != oldDate } KDatePicker::~KDatePicker() { delete d; } bool KDatePicker::eventFilter(QObject *o, QEvent *e) { if (e->type() == QEvent::KeyPress) { QKeyEvent *k = (QKeyEvent *)e; if ((k->key() == Qt::Key_PageUp) || (k->key() == Qt::Key_PageDown) || (k->key() == Qt::Key_Up) || (k->key() == Qt::Key_Down)) { QApplication::sendEvent(d->table, e); d->table->setFocus(); return true; // eat event } } return QFrame::eventFilter(o, e); } void KDatePicker::resizeEvent(QResizeEvent *e) { QWidget::resizeEvent(e); } void KDatePicker::dateChangedSlot(const QDate &date_) { d->line->setText(locale().toString(date_, QLocale::ShortFormat)); d->selectMonth->setText(locale().standaloneMonthName(date_.month(), QLocale::LongFormat)); d->fillWeeksCombo(); // calculate the item num in the week combo box; normalize selected day so as if 1.1. is the first day of the week QDate firstDay(date_.year(), 1, 1); // If we cannot successfully create the 1st of the year, this can only mean that // the 1st is before the earliest valid date in the current calendar system, so use // the earliestValidDate as the first day. // In particular covers the case of Gregorian where 1/1/-4713 is not a valid QDate d->selectWeek->setCurrentIndex((date_.dayOfYear() + firstDay.dayOfWeek() - 2) / 7); d->selectYear->setText(QString::number(date_.year()).rightJustified(4, QLatin1Char('0'))); emit dateChanged(date_); } void KDatePicker::tableClickedSlot() { emit dateSelected(date()); emit tableClicked(); } const QDate &KDatePicker::date() const { return d->table->date(); } bool KDatePicker::setDate(const QDate &date_) { // the table setDate does validity checking for us // this also emits dateChanged() which then calls our dateChangedSlot() return d->table->setDate(date_); } void KDatePicker::monthForwardClicked() { if (! setDate(date().addMonths(1))) { QApplication::beep(); } d->table->setFocus(); } void KDatePicker::monthBackwardClicked() { if (! setDate(date().addMonths(-1))) { QApplication::beep(); } d->table->setFocus(); } void KDatePicker::yearForwardClicked() { if (! setDate(d->table->date().addYears(1))) { QApplication::beep(); } d->table->setFocus(); } void KDatePicker::yearBackwardClicked() { if (! setDate(d->table->date().addYears(-1))) { QApplication::beep(); } d->table->setFocus(); } void KDatePicker::weekSelected(int index) { QDate targetDay = d->selectWeek->itemData(index).toDateTime().date(); if (! setDate(targetDay)) { QApplication::beep(); } d->table->setFocus(); } void KDatePicker::selectMonthClicked() { QDate thisDate(date()); d->table->setFocus(); QMenu popup(d->selectMonth); // Populate the pick list with all the month names, this may change by year // JPL do we need to do something here for months that fall outside valid range? const int monthsInYear = QDate(thisDate.year() + 1, 1, 1).addDays(-1).month(); for (int m = 1; m <= monthsInYear; m++) { popup.addAction(locale().standaloneMonthName(m))->setData(m); } QAction *item = popup.actions()[ thisDate.month() - 1 ]; // if this happens the above should already given an assertion if (item) { popup.setActiveAction(item); } // cancelled if ((item = popup.exec(d->selectMonth->mapToGlobal(QPoint(0, 0)), item)) == nullptr) { return; } // We need to create a valid date in the month selected so we can find out how many days are // in the month. QDate newDate(thisDate.year(), item->data().toInt(), 1); // If we have succeeded in creating a date in the new month, then try to create the new date, // checking we don't set a day after the last day of the month newDate.setDate(newDate.year(), newDate.month(), qMin(thisDate.day(), newDate.daysInMonth())); // Set the date, if it's invalid in any way then alert user and don't update if (! setDate(newDate)) { QApplication::beep(); } } void KDatePicker::selectYearClicked() { if (!d->selectYear->isChecked()) { return; } QDate thisDate(date()); KPopupFrame *popup = new KPopupFrame(this); KDatePickerPrivateYearSelector *picker = new KDatePickerPrivateYearSelector(date(), popup); picker->resize(picker->sizeHint()); picker->setYear(thisDate.year()); picker->selectAll(); popup->setMainWidget(picker); connect(picker, &KDatePickerPrivateYearSelector::closeMe, popup, &KPopupFrame::close); picker->setFocus(); if (popup->exec(d->selectYear->mapToGlobal(QPoint(0, d->selectMonth->height())))) { // We need to create a valid date in the year/month selected so we can find out how many // days are in the month. QDate newDate(picker->year(), thisDate.month(), 1); // If we have succeeded in creating a date in the new month, then try to create the new // date, checking we don't set a day after the last day of the month newDate = QDate(newDate.year(), newDate.month(), qMin(thisDate.day(), newDate.daysInMonth())); // Set the date, if it's invalid in any way then alert user and don't update if (! setDate(newDate)) { QApplication::beep(); } } delete popup; d->selectYear->setChecked(false); } void KDatePicker::uncheckYearSelector() { d->selectYear->setChecked(false); d->selectYear->update(); } void KDatePicker::changeEvent(QEvent *event) { if (event && event->type() == QEvent::EnabledChange) { if (isEnabled()) { d->table->setFocus(); } } } KDateTable *KDatePicker::dateTable() const { return d->table; } void KDatePicker::lineEnterPressed() { QDate newDate = QDate::fromString(d->line->text(), locale().dateFormat()); if (newDate.isValid()) { emit dateEntered(newDate); setDate(newDate); d->table->setFocus(); } else { QApplication::beep(); } } void KDatePicker::todayButtonClicked() { setDate(QDate::currentDate()); d->table->setFocus(); } QSize KDatePicker::sizeHint() const { return QWidget::sizeHint(); } void KDatePicker::setFontSize(int s) { QWidget *const buttons[] = { d->selectMonth, d->selectYear, }; const int NoOfButtons = sizeof(buttons) / sizeof(buttons[0]); int count; QFont font; QRect r; // ----- d->fontsize = s; for (count = 0; count < NoOfButtons; ++count) { font = buttons[count]->font(); font.setPointSize(s); buttons[count]->setFont(font); } d->table->setFontSize(s); QFontMetrics metrics(d->selectMonth->fontMetrics()); QString longestMonth; for (int i = 1;; ++i) { QString str = locale().standaloneMonthName(i, QLocale::LongFormat); if (str.isNull()) { break; } r = metrics.boundingRect(str); if (r.width() > d->maxMonthRect.width()) { d->maxMonthRect.setWidth(r.width()); longestMonth = str; } if (r.height() > d->maxMonthRect.height()) { d->maxMonthRect.setHeight(r.height()); } } QStyleOptionToolButton opt; opt.initFrom(d->selectMonth); opt.text = longestMonth; // stolen from QToolButton QSize textSize = metrics.size(Qt::TextShowMnemonic, longestMonth); textSize.setWidth(textSize.width() + metrics.width(QLatin1Char(' ')) * 2); int w = textSize.width(); int h = textSize.height(); opt.rect.setHeight(h); // PM_MenuButtonIndicator depends on the height QSize metricBound = style()->sizeFromContents( QStyle::CT_ToolButton, &opt, QSize(w, h), d->selectMonth ).expandedTo(QApplication::globalStrut()); d->selectMonth->setMinimumSize(metricBound); } int KDatePicker::fontSize() const { return d->fontsize; } void KDatePicker::setCloseButton(bool enable) { if (enable == (d->closeButton != nullptr)) { return; } if (enable) { d->closeButton = new QToolButton(this); d->closeButton->setAutoRaise(true); const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); d->navigationLayout->addSpacing(spacingHint); d->navigationLayout->addWidget(d->closeButton); d->closeButton->setToolTip(tr("Close", "@action:button")); d->closeButton->setIcon(QIcon::fromTheme(QStringLiteral("window-close"))); connect(d->closeButton, &QAbstractButton::clicked, topLevelWidget(), &QWidget::close); } else { delete d->closeButton; d->closeButton = nullptr; } updateGeometry(); } bool KDatePicker::hasCloseButton() const { return (d->closeButton); } #include "kdatepicker.moc" diff --git a/src/kdatepicker.h b/src/kdatepicker.h index 340385f..8d6eebc 100644 --- a/src/kdatepicker.h +++ b/src/kdatepicker.h @@ -1,185 +1,184 @@ /* -*- C++ -*- This file is part of the KDE libraries Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) (C) 1998-2001 Mirko Boehm (mirko@kde.org) (C) 2007 John Layt This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDATEPICKER_H #define KDATEPICKER_H #include -#include #include class QLineEdit; class KDateTable; /** * @class KDatePicker kdatepicker.h KDatePicker * * @short A date selection widget. * * Provides a widget for calendar date input. * * Different from the * previous versions, it now emits two types of signals, either * dateSelected() or dateEntered() (see documentation for both * signals). * * A line edit has been added in the newer versions to allow the user * to select a date directly by entering numbers like 19990101 * or 990101. * * \image html kdatepicker.png "KDatePicker Widget" * * @author Tim Gilman, Mirko Boehm * **/ class KWIDGETSADDONS_EXPORT KDatePicker: public QFrame { Q_OBJECT Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged USER true) Q_PROPERTY(bool closeButton READ hasCloseButton WRITE setCloseButton) Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize) public: /** * The constructor. The current date will be displayed initially. **/ explicit KDatePicker(QWidget *parent = nullptr); /** * The constructor. The given date will be displayed initially. **/ explicit KDatePicker(const QDate &dt, QWidget *parent = nullptr); /** * The destructor. **/ ~KDatePicker() override; /** The size hint for date pickers. The size hint recommends the * minimum size of the widget so that all elements may be placed * without clipping. This sometimes looks ugly, so when using the * size hint, try adding 28 to each of the reported numbers of * pixels. **/ QSize sizeHint() const override; /** * Sets the date. * * @returns @p false and does not change anything if the date given is invalid. **/ bool setDate(const QDate &date); /** * @returns the selected date. */ const QDate &date() const; /** * @returns the KDateTable widget child of this KDatePicker * widget. */ /** * Sets the font size of the widgets elements. **/ void setFontSize(int); /** * Returns the font size of the widget elements. */ int fontSize() const; /** * By calling this method with @p enable = true, KDatePicker will show * a little close-button in the upper button-row. Clicking the * close-button will cause the KDatePicker's topLevelWidget()'s close() * method being called. This is mostly useful for toplevel datepickers * without a window manager decoration. * @see hasCloseButton */ void setCloseButton(bool enable); /** * @returns true if a KDatePicker shows a close-button. * @see setCloseButton */ bool hasCloseButton() const; protected: /// to catch move keyEvents when QLineEdit has keyFocus bool eventFilter(QObject *o, QEvent *e) override; /// the resize event void resizeEvent(QResizeEvent *) override; void changeEvent(QEvent *event) override; protected Q_SLOTS: void dateChangedSlot(const QDate &date); void tableClickedSlot(); void monthForwardClicked(); void monthBackwardClicked(); void yearForwardClicked(); void yearBackwardClicked(); void selectMonthClicked(); void selectYearClicked(); void uncheckYearSelector(); void lineEnterPressed(); void todayButtonClicked(); void weekSelected(int); Q_SIGNALS: /** This signal is emitted each time the selected date is changed. * Usually, this does not mean that the date has been entered, * since the date also changes, for example, when another month is * selected. * @see dateSelected */ void dateChanged(const QDate &date); /** This signal is emitted each time a day has been selected by * clicking on the table (hitting a day in the current month). It * has the same meaning as dateSelected() in older versions of * KDatePicker. */ void dateSelected(const QDate &date); /** This signal is emitted when enter is pressed and a VALID date * has been entered before into the line edit. Connect to both * dateEntered() and dateSelected() to receive all events where the * user really enters a date. */ void dateEntered(const QDate &date); /** This signal is emitted when the day has been selected by * clicking on it in the table. */ void tableClicked(); private: KDateTable *dateTable() const; void initWidget(const QDate &date); class KDatePickerPrivate; friend class KDatePickerPrivate; KDatePickerPrivate *const d; }; #endif // KDATEPICKER_H diff --git a/src/kdatetimeedit.cpp b/src/kdatetimeedit.cpp index b385b0b..7ef7e7c 100644 --- a/src/kdatetimeedit.cpp +++ b/src/kdatetimeedit.cpp @@ -1,560 +1,555 @@ /* Copyright 2011 John Layt This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kdatetimeedit.h" -#include -#include -#include -#include -#include #include "kdatepicker.h" #include "kdatecombobox.h" #include "kmessagebox.h" #include "ui_kdatetimeedit.h" class KDateTimeEditPrivate { public: KDateTimeEditPrivate(KDateTimeEdit *q); virtual ~KDateTimeEditPrivate(); QDateTime defaultMinDateTime(); QDateTime defaultMaxDateTime(); void initWidgets(); void initDateWidget(); void initTimeWidget(); void initCalendarWidget(); void updateCalendarWidget(); void initTimeZoneWidget(); void updateTimeZoneWidget(); void warnDateTime(); //private Q_SLOTS: void selectCalendar(int index); void enterCalendar(const QLocale &calendarLocale); void selectTimeZone(int index); void enterTimeZone(const QByteArray &zoneId); KDateTimeEdit *const q; KDateTimeEdit::Options m_options; QDateTime m_dateTime; QDateTime m_minDateTime; QDateTime m_maxDateTime; QString m_minWarnMsg; QString m_maxWarnMsg; QList m_calendarLocales; QList m_zones; Ui::KDateTimeEdit ui; }; KDateTimeEditPrivate::KDateTimeEditPrivate(KDateTimeEdit *q) : q(q) { m_options = KDateTimeEdit::ShowDate | KDateTimeEdit::EditDate | KDateTimeEdit::SelectDate | KDateTimeEdit::ShowTime | KDateTimeEdit::EditTime | KDateTimeEdit::SelectTime | KDateTimeEdit::DatePicker | KDateTimeEdit::DateKeywords; m_dateTime = QDateTime::currentDateTime(); m_dateTime.setTime(QTime(0, 0, 0)); m_calendarLocales << q->locale(); foreach (const QByteArray &zoneId, QTimeZone::availableTimeZoneIds()) { m_zones << QTimeZone(zoneId); } } KDateTimeEditPrivate::~KDateTimeEditPrivate() { } QDateTime KDateTimeEditPrivate::defaultMinDateTime() { // TODO: Find a way to get it from QLocale //return KDateTime(calendar()->earliestValidDate(), QTime(0, 0, 0, 0)); return QDateTime(); } QDateTime KDateTimeEditPrivate::defaultMaxDateTime() { // TODO: Find a way to get it from QLocale //return KDateTime(calendar()->latestValidDate(), QTime(23, 59, 59, 999)); return QDateTime(); } void KDateTimeEditPrivate::initWidgets() { initDateWidget(); initTimeWidget(); initCalendarWidget(); initTimeZoneWidget(); } void KDateTimeEditPrivate::initDateWidget() { ui.m_dateCombo->blockSignals(true); ui.m_dateCombo->setVisible((m_options & KDateTimeEdit::ShowDate) == KDateTimeEdit::ShowDate); KDateComboBox::Options options; if ((m_options & KDateTimeEdit::EditDate) == KDateTimeEdit::EditDate) { options = options | KDateComboBox::EditDate; } if ((m_options & KDateTimeEdit::SelectDate) == KDateTimeEdit::SelectDate) { options = options | KDateComboBox::SelectDate; } if ((m_options & KDateTimeEdit::DatePicker) == KDateTimeEdit::DatePicker) { options = options | KDateComboBox::DatePicker; } if ((m_options & KDateTimeEdit::DateKeywords) == KDateTimeEdit::DateKeywords) { options = options | KDateComboBox::DateKeywords; } ui.m_dateCombo->setOptions(options); ui.m_dateCombo->blockSignals(false); } void KDateTimeEditPrivate::initTimeWidget() { ui.m_timeCombo->blockSignals(true); ui.m_timeCombo->setVisible((m_options & KDateTimeEdit::ShowTime) == KDateTimeEdit::ShowTime); KTimeComboBox::Options options; if ((m_options & KDateTimeEdit::EditTime) == KDateTimeEdit::EditTime) { options = options | KTimeComboBox::EditTime; } if ((m_options & KDateTimeEdit::SelectTime) == KDateTimeEdit::SelectTime) { options = options | KTimeComboBox::SelectTime; } if ((m_options & KDateTimeEdit::ForceTime) == KDateTimeEdit::ForceTime) { options = options | KTimeComboBox::ForceTime; } ui.m_timeCombo->setOptions(options); ui.m_timeCombo->blockSignals(false); } void KDateTimeEditPrivate::initCalendarWidget() { ui.m_calendarCombo->blockSignals(true); ui.m_calendarCombo->clear(); foreach (const QLocale &calendarLocale, m_calendarLocales) { ui.m_calendarCombo->addItem(calendarLocale.name(), calendarLocale); } ui.m_calendarCombo->setCurrentIndex(ui.m_calendarCombo->findData(q->locale())); ui.m_calendarCombo->setVisible((m_options & KDateTimeEdit::ShowCalendar) == KDateTimeEdit::ShowCalendar); ui.m_calendarCombo->setEnabled((m_options & KDateTimeEdit::SelectCalendar) == KDateTimeEdit::SelectCalendar); ui.m_calendarCombo->setEditable(false); ui.m_calendarCombo->blockSignals(false); } void KDateTimeEditPrivate::updateCalendarWidget() { ui.m_calendarCombo->blockSignals(true); ui.m_calendarCombo->setCurrentIndex(ui.m_calendarCombo->findData(q->locale())); ui.m_calendarCombo->blockSignals(false); } void KDateTimeEditPrivate::selectCalendar(int index) { enterCalendar(ui.m_calendarCombo->itemData(index).toLocale()); } void KDateTimeEditPrivate::enterCalendar(const QLocale &calendarLocale) { q->setLocale(calendarLocale); emit q->calendarEntered(q->locale()); } void KDateTimeEditPrivate::initTimeZoneWidget() { ui.m_timeZoneCombo->blockSignals(true); ui.m_timeZoneCombo->clear(); ui.m_timeZoneCombo->addItem(KDateTimeEdit::tr("UTC", "UTC time zone"), QByteArray("UTC")); ui.m_timeZoneCombo->addItem(KDateTimeEdit::tr("Floating", "No specific time zone"), QByteArray()); foreach (const QTimeZone &zone, m_zones) { ui.m_timeZoneCombo->addItem(QString::fromUtf8(zone.id()), zone.id()); } ui.m_timeZoneCombo->setVisible((m_options & KDateTimeEdit::ShowTimeZone) == KDateTimeEdit::ShowTimeZone); ui.m_timeZoneCombo->setEnabled((m_options & KDateTimeEdit::SelectTimeZone) == KDateTimeEdit::SelectTimeZone); ui.m_timeZoneCombo->setEditable(false); ui.m_timeZoneCombo->blockSignals(false); } void KDateTimeEditPrivate::updateTimeZoneWidget() { ui.m_timeZoneCombo->blockSignals(true); ui.m_timeZoneCombo->blockSignals(false); } void KDateTimeEditPrivate::selectTimeZone(int index) { enterTimeZone(ui.m_timeCombo->itemData(index).toByteArray()); } void KDateTimeEditPrivate::enterTimeZone(const QByteArray &zoneId) { q->setTimeZone(QTimeZone(zoneId)); emit q->dateTimeEntered(m_dateTime); emit q->timeZoneEntered(m_dateTime.timeZone()); } void KDateTimeEditPrivate::warnDateTime() { if (!q->isValid() && (m_options & KDateTimeEdit::WarnOnInvalid) == KDateTimeEdit::WarnOnInvalid) { QString warnMsg; if (!m_dateTime.isValid()) { //TODO Add missing string //warnMsg = tr("The date or time you entered is invalid"); } else if (m_minDateTime.isValid() && m_dateTime < m_minDateTime) { if (m_minWarnMsg.isEmpty()) { //TODO Add datetime to string //warnMsg = q->tr("Date and time cannot be earlier than %1", "@info").arg(formatDate(m_minDate)); warnMsg = KDateTimeEdit::tr("The entered date and time is before the minimum allowed date and time.", "@info"); } else { warnMsg = m_minWarnMsg; //TODO localize properly warnMsg.replace(QStringLiteral("%1"), q->locale().toString(m_minDateTime)); } } else if (m_maxDateTime.isValid() && m_dateTime > m_maxDateTime) { if (m_maxWarnMsg.isEmpty()) { //TODO Add datetime to string //warnMsg = q->tr("Date cannot be later than %1", "@info").arg(formatDate(m_maxDate)); warnMsg = KDateTimeEdit::tr("The entered date and time is after the maximum allowed date and time.", "@info"); } else { warnMsg = m_maxWarnMsg; warnMsg.replace(QStringLiteral("%1"), q->locale().toString(m_maxDateTime)); } } KMessageBox::sorry(q, warnMsg); } } KDateTimeEdit::KDateTimeEdit(QWidget *parent) : QWidget(parent), d(new KDateTimeEditPrivate(this)) { d->ui.setupUi(this); //Need to do the min/max defaults here and not in private init as need to wait for ui to init //the KDateComboBox which holds the calendar object. Revisit this??? d->m_minDateTime = d->defaultMinDateTime(); d->m_maxDateTime = d->defaultMaxDateTime(); d->ui.m_calendarCombo->installEventFilter(this); d->ui.m_dateCombo->installEventFilter(this); d->ui.m_timeCombo->installEventFilter(this); d->ui.m_timeZoneCombo->installEventFilter(this); d->initWidgets(); connect(d->ui.m_dateCombo, &KDateComboBox::dateChanged, this, &KDateTimeEdit::setDate); connect(d->ui.m_timeCombo, &KTimeComboBox::timeChanged, this, &KDateTimeEdit::setTime); connect(d->ui.m_calendarCombo, SIGNAL(activated(int)), this, SLOT(selectCalendar(int))); connect(d->ui.m_timeZoneCombo, SIGNAL(activated(int)), this, SLOT(selectTimeZone(int))); } KDateTimeEdit::~KDateTimeEdit() { delete d; } QDateTime KDateTimeEdit::dateTime() const { return d->m_dateTime; } QDate KDateTimeEdit::date() const { return d->m_dateTime.date(); } QTime KDateTimeEdit::time() const { return d->m_dateTime.time(); } QTimeZone KDateTimeEdit::timeZone() const { return d->m_dateTime.timeZone(); } bool KDateTimeEdit::isValid() const { return d->m_dateTime.isValid() && (!d->m_minDateTime.isValid() || d->m_dateTime >= d->m_minDateTime) && (!d->m_maxDateTime.isValid() || d->m_dateTime <= d->m_maxDateTime); } bool KDateTimeEdit::isNull() const { return isNullDate() && isNullTime(); } bool KDateTimeEdit::isValidDate() const { return d->ui.m_dateCombo->isValid(); } bool KDateTimeEdit::isNullDate() const { return d->ui.m_dateCombo->isNull(); } bool KDateTimeEdit::isValidTime() const { return d->ui.m_timeCombo->isValid(); } bool KDateTimeEdit::isNullTime() const { return d->ui.m_timeCombo->isNull(); } void KDateTimeEdit::setOptions(Options options) { if (options != d->m_options) { d->m_options = options; d->initWidgets(); } } KDateTimeEdit::Options KDateTimeEdit::options() const { return d->m_options; } void KDateTimeEdit::setDateTime(const QDateTime &dateTime) { if (dateTime != d->m_dateTime) { assignDateTime(dateTime); emit dateTimeChanged(d->m_dateTime); emit dateChanged(d->m_dateTime.date()); emit timeChanged(d->m_dateTime.time()); } } void KDateTimeEdit::assignDateTime(const QDateTime &dateTime) { d->m_dateTime = dateTime; d->ui.m_dateCombo->setDate(dateTime.date()); d->ui.m_timeCombo->setTime(dateTime.time()); } void KDateTimeEdit::setDate(const QDate &date) { if (date != d->m_dateTime.date()) { assignDate(date); emit dateTimeChanged(d->m_dateTime); emit dateChanged(d->m_dateTime.date()); } } void KDateTimeEdit::assignDate(const QDate &date) { d->m_dateTime.setDate(date); d->ui.m_dateCombo->setDate(date); } void KDateTimeEdit::setTime(const QTime &time) { if (time != d->m_dateTime.time()) { assignTime(time); emit dateTimeChanged(d->m_dateTime); emit timeChanged(d->m_dateTime.time()); } } void KDateTimeEdit::assignTime(const QTime &time) { d->m_dateTime.setTime(time); d->ui.m_timeCombo->setTime(time); } void KDateTimeEdit::setTimeZone(const QTimeZone &zone) { if (zone == d->m_dateTime.timeZone() || !zone.isValid()) { return; } assignTimeZone(zone); emit dateTimeChanged(d->m_dateTime); emit timeZoneChanged(d->m_dateTime.timeZone()); } void KDateTimeEdit::assignTimeZone(const QTimeZone &zone) { d->m_dateTime.setTimeZone(zone); d->updateTimeZoneWidget(); } void KDateTimeEdit::setMinimumDateTime(const QDateTime &minDateTime, const QString &minWarnMsg) { setDateTimeRange(minDateTime, maximumDateTime(), minWarnMsg, d->m_maxWarnMsg); } QDateTime KDateTimeEdit::minimumDateTime() const { return d->m_minDateTime; } void KDateTimeEdit::resetMinimumDateTime() { d->m_minDateTime = d->defaultMinDateTime(); } void KDateTimeEdit::setMaximumDateTime(const QDateTime &maxDateTime, const QString &maxWarnMsg) { setDateTimeRange(minimumDateTime(), maxDateTime, d->m_minWarnMsg, maxWarnMsg); } QDateTime KDateTimeEdit::maximumDateTime() const { return d->m_maxDateTime; } void KDateTimeEdit::resetMaximumDateTime() { d->m_maxDateTime = d->defaultMaxDateTime(); } void KDateTimeEdit::setDateTimeRange(const QDateTime &minDateTime, const QDateTime &maxDateTime, const QString &minErrorMsg, const QString &maxErrorMsg) { if (minDateTime.isValid() && maxDateTime.isValid() && minDateTime <= maxDateTime) { d->m_minDateTime = minDateTime; d->m_minWarnMsg = minErrorMsg; d->m_maxDateTime = maxDateTime; d->m_maxWarnMsg = maxErrorMsg; } } void KDateTimeEdit::resetDateTimeRange() { setDateTimeRange(d->defaultMinDateTime(), d->defaultMaxDateTime()); } void KDateTimeEdit::setCalendarLocalesList(const QList &calendarLocales) { if (calendarLocales != d->m_calendarLocales) { d->m_calendarLocales = calendarLocales; d->updateCalendarWidget(); } } QList KDateTimeEdit::calendarLocalesList() const { return d->m_calendarLocales; } void KDateTimeEdit::setDateDisplayFormat(QLocale::FormatType format) { d->ui.m_dateCombo->setDisplayFormat(format); } QLocale::FormatType KDateTimeEdit::dateDisplayFormat() const { return d->ui.m_dateCombo->displayFormat(); } void KDateTimeEdit::setDateMap(QMap dateMap) { d->ui.m_dateCombo->setDateMap(dateMap); } QMap KDateTimeEdit::dateMap() const { return d->ui.m_dateCombo->dateMap(); } void KDateTimeEdit::setTimeDisplayFormat(QLocale::FormatType formatOptions) { d->ui.m_timeCombo->setDisplayFormat(formatOptions); } QLocale::FormatType KDateTimeEdit::timeDisplayFormat() const { return d->ui.m_timeCombo->displayFormat(); } void KDateTimeEdit::setTimeListInterval(int minutes) { d->ui.m_timeCombo->setTimeListInterval(minutes); } int KDateTimeEdit::timeListInterval() const { return d->ui.m_timeCombo->timeListInterval(); } void KDateTimeEdit::setTimeList(QList timeList, const QString &minWarnMsg, const QString &maxWarnMsg) { d->ui.m_timeCombo->setTimeList(timeList, minWarnMsg, maxWarnMsg); } QList KDateTimeEdit::timeList() const { return d->ui.m_timeCombo->timeList(); } void KDateTimeEdit::setTimeZones(const QList &zones) { if (zones != d->m_zones) { d->m_zones = zones; d->updateTimeZoneWidget(); } } QList KDateTimeEdit::timeZones() const { return d->m_zones; } bool KDateTimeEdit::eventFilter(QObject *object, QEvent *event) { return QWidget::eventFilter(object, event); } void KDateTimeEdit::focusInEvent(QFocusEvent *event) { QWidget::focusInEvent(event); } void KDateTimeEdit::focusOutEvent(QFocusEvent *event) { d->warnDateTime(); QWidget::focusOutEvent(event); } void KDateTimeEdit::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); } #include "moc_kdatetimeedit.cpp" diff --git a/src/keditlistwidget.cpp b/src/keditlistwidget.cpp index 1fc6acf..902bc38 100644 --- a/src/keditlistwidget.cpp +++ b/src/keditlistwidget.cpp @@ -1,675 +1,675 @@ /* This file is part of the KDE libraries Copyright (C) 2000 David Faure , Alexander Neundorf (C) 2000, 2002 Carsten Pfeiffer (C) 2010 Sebastian Trueg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "keditlistwidget.h" #include #include -#include -#include #include #include #include #include #include #include +#include +#include class KEditListWidgetPrivate { public: KEditListWidgetPrivate(KEditListWidget *parent) : lineEdit(nullptr), editingWidget(nullptr), q(parent) { } QListView *listView = nullptr; QPushButton *servUpButton = nullptr; QPushButton *servDownButton = nullptr; QPushButton *servNewButton = nullptr; QPushButton *servRemoveButton = nullptr; QLineEdit *lineEdit = nullptr; QWidget *editingWidget = nullptr; QVBoxLayout *mainLayout = nullptr; QVBoxLayout *btnsLayout = nullptr; QStringListModel *model = nullptr; bool checkAtEntering; KEditListWidget::Buttons buttons; void init(bool check = false, KEditListWidget::Buttons buttons = KEditListWidget::All, QWidget *representationWidget = nullptr); void setEditor(QLineEdit *lineEdit, QWidget *representationWidget = nullptr); void updateButtonState(); QModelIndex selectedIndex(); private: KEditListWidget *q; }; void KEditListWidgetPrivate::init(bool check, KEditListWidget::Buttons newButtons, QWidget *representationWidget) { checkAtEntering = check; servNewButton = servRemoveButton = servUpButton = servDownButton = nullptr; q->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred)); mainLayout = new QVBoxLayout(q); mainLayout->setContentsMargins(0, 0, 0, 0); QHBoxLayout *subLayout = new QHBoxLayout; btnsLayout = new QVBoxLayout; btnsLayout->addStretch(); model = new QStringListModel(); listView = new QListView(q); listView->setModel(model); subLayout->addWidget(listView); subLayout->addLayout(btnsLayout); mainLayout->insertLayout(1, subLayout); setEditor(lineEdit, representationWidget); buttons = KEditListWidget::Buttons(); q->setButtons(newButtons); q->connect(listView->selectionModel(), &QItemSelectionModel::selectionChanged, q, &KEditListWidget::slotSelectionChanged); } void KEditListWidgetPrivate::setEditor(QLineEdit *newLineEdit, QWidget *representationWidget) { if (editingWidget != lineEdit && editingWidget != representationWidget) { delete editingWidget; } if (lineEdit != newLineEdit) { delete lineEdit; } lineEdit = newLineEdit ? newLineEdit : new QLineEdit(q); editingWidget = representationWidget ? representationWidget : lineEdit; if (representationWidget) { representationWidget->setParent(q); } mainLayout->insertWidget(0, editingWidget); lineEdit->installEventFilter(q); q->connect(lineEdit, &QLineEdit::textChanged, q, &KEditListWidget::typedSomething); q->connect(lineEdit, &QLineEdit::returnPressed, q, &KEditListWidget::addItem); // maybe supplied lineedit has some text already q->typedSomething(lineEdit->text()); // fix tab ordering q->setTabOrder(editingWidget, listView); QWidget *w = listView; if (servNewButton) { q->setTabOrder(w, servNewButton); w = servNewButton; } if (servRemoveButton) { q->setTabOrder(w, servRemoveButton); w = servRemoveButton; } if (servUpButton) { q->setTabOrder(w, servUpButton); w = servUpButton; } if (servDownButton) { q->setTabOrder(w, servDownButton); w = servDownButton; } } void KEditListWidgetPrivate::updateButtonState() { const bool hasSelectedItem = selectedIndex().isValid(); // TODO: merge with enableMoveButtons() QPushButton * const buttons[3] = { servUpButton, servDownButton, servRemoveButton }; for (QPushButton *button : buttons) { if (button) { // keep focus in widget if (!hasSelectedItem && button->hasFocus()) { lineEdit->setFocus(Qt::OtherFocusReason); } button->setEnabled(hasSelectedItem); } } } QModelIndex KEditListWidgetPrivate::selectedIndex() { QItemSelectionModel *selection = listView->selectionModel(); const QModelIndexList selectedIndexes = selection->selectedIndexes(); if (!selectedIndexes.isEmpty() && selectedIndexes[0].isValid()) { return selectedIndexes[0]; } else { return QModelIndex(); } } class Q_DECL_HIDDEN KEditListWidget::CustomEditorPrivate { public: CustomEditorPrivate(KEditListWidget::CustomEditor *q): q(q), representationWidget(nullptr), lineEdit(nullptr) {} KEditListWidget::CustomEditor *q; QWidget *representationWidget; QLineEdit *lineEdit; }; KEditListWidget::CustomEditor::CustomEditor() : d(new CustomEditorPrivate(this)) { } KEditListWidget::CustomEditor::CustomEditor(QWidget *repWidget, QLineEdit *edit) : d(new CustomEditorPrivate(this)) { d->representationWidget = repWidget; d->lineEdit = edit; } KEditListWidget::CustomEditor::CustomEditor(QComboBox *combo) : d(new CustomEditorPrivate(this)) { d->representationWidget = combo; d->lineEdit = qobject_cast(combo->lineEdit()); Q_ASSERT(d->lineEdit); } KEditListWidget::CustomEditor::~CustomEditor() { delete d; } void KEditListWidget::CustomEditor::setRepresentationWidget(QWidget *repWidget) { d->representationWidget = repWidget; } void KEditListWidget::CustomEditor::setLineEdit(QLineEdit *edit) { d->lineEdit = edit; } QWidget *KEditListWidget::CustomEditor::representationWidget() const { return d->representationWidget; } QLineEdit *KEditListWidget::CustomEditor::lineEdit() const { return d->lineEdit; } KEditListWidget::KEditListWidget(QWidget *parent) : QWidget(parent), d(new KEditListWidgetPrivate(this)) { d->init(); } KEditListWidget::KEditListWidget(const CustomEditor &custom, QWidget *parent, bool checkAtEntering, Buttons buttons) : QWidget(parent), d(new KEditListWidgetPrivate(this)) { d->lineEdit = custom.lineEdit(); d->init(checkAtEntering, buttons, custom.representationWidget()); } KEditListWidget::~KEditListWidget() { delete d; } void KEditListWidget::setCustomEditor(const CustomEditor &editor) { d->setEditor(editor.lineEdit(), editor.representationWidget()); } QListView *KEditListWidget::listView() const { return d->listView; } QLineEdit *KEditListWidget::lineEdit() const { return d->lineEdit; } QPushButton *KEditListWidget::addButton() const { return d->servNewButton; } QPushButton *KEditListWidget::removeButton() const { return d->servRemoveButton; } QPushButton *KEditListWidget::upButton() const { return d->servUpButton; } QPushButton *KEditListWidget::downButton() const { return d->servDownButton; } int KEditListWidget::count() const { return int(d->model->rowCount()); } void KEditListWidget::setButtons(Buttons buttons) { if (d->buttons == buttons) { return; } if ((buttons & Add) && !d->servNewButton) { d->servNewButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-add")), tr("&Add"), this); d->servNewButton->setEnabled(false); d->servNewButton->show(); connect(d->servNewButton, &QAbstractButton::clicked, this, &KEditListWidget::addItem); d->btnsLayout->insertWidget(0, d->servNewButton); } else if ((buttons & Add) == 0 && d->servNewButton) { delete d->servNewButton; d->servNewButton = nullptr; } if ((buttons & Remove) && !d->servRemoveButton) { d->servRemoveButton = new QPushButton(QIcon::fromTheme(QStringLiteral("list-remove")), tr("&Remove"), this); d->servRemoveButton->setEnabled(false); d->servRemoveButton->show(); connect(d->servRemoveButton, &QAbstractButton::clicked, this, &KEditListWidget::removeItem); d->btnsLayout->insertWidget(1, d->servRemoveButton); } else if ((buttons & Remove) == 0 && d->servRemoveButton) { delete d->servRemoveButton; d->servRemoveButton = nullptr; } if ((buttons & UpDown) && !d->servUpButton) { d->servUpButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-up")), tr("Move &Up"), this); d->servUpButton->setEnabled(false); d->servUpButton->show(); connect(d->servUpButton, &QAbstractButton::clicked, this, &KEditListWidget::moveItemUp); d->servDownButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-down")), tr("Move &Down"), this); d->servDownButton->setEnabled(false); d->servDownButton->show(); connect(d->servDownButton, &QAbstractButton::clicked, this, &KEditListWidget::moveItemDown); d->btnsLayout->insertWidget(2, d->servUpButton); d->btnsLayout->insertWidget(3, d->servDownButton); } else if ((buttons & UpDown) == 0 && d->servUpButton) { delete d->servUpButton; d->servUpButton = nullptr; delete d->servDownButton; d->servDownButton = nullptr; } d->buttons = buttons; } void KEditListWidget::setCheckAtEntering(bool check) { d->checkAtEntering = check; } bool KEditListWidget::checkAtEntering() { return d->checkAtEntering; } void KEditListWidget::typedSomething(const QString &text) { if (currentItem() >= 0) { if (currentText() != d->lineEdit->text()) { // IMHO changeItem() shouldn't do anything with the value // of currentItem() ... like changing it or emitting signals ... // but TT disagree with me on this one (it's been that way since ages ... grrr) bool block = d->listView->signalsBlocked(); d->listView->blockSignals(true); QModelIndex currentIndex = d->selectedIndex(); if (currentIndex.isValid()) { d->model->setData(currentIndex, text); } d->listView->blockSignals(block); emit changed(); } } if (!d->servNewButton) { return; } if (!d->lineEdit->hasAcceptableInput()) { d->servNewButton->setEnabled(false); return; } if (!d->checkAtEntering) { d->servNewButton->setEnabled(!text.isEmpty()); } else { if (text.isEmpty()) { d->servNewButton->setEnabled(false); } else { QStringList list = d->model->stringList(); bool enable = !list.contains(text, Qt::CaseSensitive); d->servNewButton->setEnabled(enable); } } } void KEditListWidget::moveItemUp() { if (!d->listView->isEnabled()) { QApplication::beep(); return; } QModelIndex index = d->selectedIndex(); if (index.isValid()) { if (index.row() == 0) { QApplication::beep(); return; } QModelIndex aboveIndex = d->model->index(index.row() - 1, index.column()); QString tmp = d->model->data(aboveIndex, Qt::DisplayRole).toString(); d->model->setData(aboveIndex, d->model->data(index, Qt::DisplayRole)); d->model->setData(index, tmp); d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect); d->listView->selectionModel()->select(aboveIndex, QItemSelectionModel::Select); } emit changed(); } void KEditListWidget::moveItemDown() { if (!d->listView->isEnabled()) { QApplication::beep(); return; } QModelIndex index = d->selectedIndex(); if (index.isValid()) { if (index.row() == d->model->rowCount() - 1) { QApplication::beep(); return; } QModelIndex belowIndex = d->model->index(index.row() + 1, index.column()); QString tmp = d->model->data(belowIndex, Qt::DisplayRole).toString(); d->model->setData(belowIndex, d->model->data(index, Qt::DisplayRole)); d->model->setData(index, tmp); d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect); d->listView->selectionModel()->select(belowIndex, QItemSelectionModel::Select); } emit changed(); } void KEditListWidget::addItem() { // when checkAtEntering is true, the add-button is disabled, but this // slot can still be called through Key_Return/Key_Enter. So we guard // against this. if (!d->servNewButton || !d->servNewButton->isEnabled()) { return; } QModelIndex currentIndex = d->selectedIndex(); const QString ¤tTextLE = d->lineEdit->text(); bool alreadyInList(false); //if we didn't check for dupes at the inserting we have to do it now if (!d->checkAtEntering) { // first check current item instead of dumb iterating the entire list if (currentIndex.isValid()) { if (d->model->data(currentIndex, Qt::DisplayRole).toString() == currentTextLE) { alreadyInList = true; } } else { alreadyInList = d->model->stringList().contains(currentTextLE, Qt::CaseSensitive); } } if (d->servNewButton) { // prevent losing the focus by it being moved outside of this widget // as well as support the user workflow a little by moving the focus // to the lineedit. chances are that users will add some items consecutively, // so this will save a manual focus change, and it is also consistent // to what happens on the click on the Remove button if (d->servNewButton->hasFocus()) { d->lineEdit->setFocus(Qt::OtherFocusReason); } d->servNewButton->setEnabled(false); } bool block = d->lineEdit->signalsBlocked(); d->lineEdit->blockSignals(true); d->lineEdit->clear(); d->lineEdit->blockSignals(block); d->listView->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::Deselect); if (!alreadyInList) { block = d->listView->signalsBlocked(); if (currentIndex.isValid()) { d->model->setData(currentIndex, currentTextLE); } else { QStringList lst; lst << currentTextLE; lst << d->model->stringList(); d->model->setStringList(lst); } emit changed(); emit added(currentTextLE); // TODO: pass the index too } d->updateButtonState(); } int KEditListWidget::currentItem() const { QModelIndex selectedIndex = d->selectedIndex(); if (selectedIndex.isValid()) { return selectedIndex.row(); } else { return -1; } } void KEditListWidget::removeItem() { QModelIndex currentIndex = d->selectedIndex(); if (!currentIndex.isValid()) { return; } if (currentIndex.row() >= 0) { // prevent losing the focus by it being moved outside of this widget // as well as support the user workflow a little by moving the focus // to the lineedit. chances are that users will add some item next, // so this will save a manual focus change, if (d->servRemoveButton && d->servRemoveButton->hasFocus()) { d->lineEdit->setFocus(Qt::OtherFocusReason); } QString removedText = d->model->data(currentIndex, Qt::DisplayRole).toString(); d->model->removeRows(currentIndex.row(), 1); d->listView->selectionModel()->clear(); emit changed(); emit removed(removedText); } d->updateButtonState(); } void KEditListWidget::enableMoveButtons(const QModelIndex &newIndex, const QModelIndex &) { int index = newIndex.row(); // Update the lineEdit when we select a different line. if (currentText() != d->lineEdit->text()) { d->lineEdit->setText(currentText()); } bool moveEnabled = d->servUpButton && d->servDownButton; if (moveEnabled) { if (d->model->rowCount() <= 1) { d->servUpButton->setEnabled(false); d->servDownButton->setEnabled(false); } else if (index == (d->model->rowCount() - 1)) { d->servUpButton->setEnabled(true); d->servDownButton->setEnabled(false); } else if (index == 0) { d->servUpButton->setEnabled(false); d->servDownButton->setEnabled(true); } else { d->servUpButton->setEnabled(true); d->servDownButton->setEnabled(true); } } if (d->servRemoveButton) { d->servRemoveButton->setEnabled(true); } } void KEditListWidget::clear() { d->lineEdit->clear(); d->model->setStringList(QStringList()); emit changed(); } void KEditListWidget::insertStringList(const QStringList &list, int index) { QStringList content = d->model->stringList(); if (index < 0) { content += list; } else for (int i = 0, j = index; i < list.count(); ++i, ++j) { content.insert(j, list[ i ]); } d->model->setStringList(content); } void KEditListWidget::insertItem(const QString &text, int index) { QStringList list = d->model->stringList(); if (index < 0) { list.append(text); } else { list.insert(index, text); } d->model->setStringList(list); } QString KEditListWidget::text(int index) const { const QStringList list = d->model->stringList(); return list[ index ]; } QString KEditListWidget::currentText() const { QModelIndex index = d->selectedIndex(); if (!index.isValid()) { return QString(); } else { return text(index.row()); } } QStringList KEditListWidget::items() const { return d->model->stringList(); } void KEditListWidget::setItems(const QStringList &items) { d->model->setStringList(items); } KEditListWidget::Buttons KEditListWidget::buttons() const { return d->buttons; } void KEditListWidget::slotSelectionChanged(const QItemSelection &, const QItemSelection &) { d->updateButtonState(); QModelIndex index = d->selectedIndex(); enableMoveButtons(index, QModelIndex()); if (index.isValid()) { d->lineEdit->setFocus(Qt::OtherFocusReason); } } bool KEditListWidget::eventFilter(QObject *o, QEvent *e) { if (o == d->lineEdit && e->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = (QKeyEvent *)e; if (keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_Up) { return ((QObject *)d->listView)->event(e); } else if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { return true; } } return false; } diff --git a/src/kfontaction.cpp b/src/kfontaction.cpp index afcc187..b30b62f 100644 --- a/src/kfontaction.cpp +++ b/src/kfontaction.cpp @@ -1,215 +1,213 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2002 Joseph Wenninger (C) 2003 Andras Mantia (C) 2005-2006 Hamish Rodda (C) 2007 Clarence Dang This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kfontaction.h" -#include #include -#include #include class Q_DECL_HIDDEN KFontAction::KFontActionPrivate { public: KFontActionPrivate(KFontAction *parent) : q(parent), settingFont(0), fontFilters(QFontComboBox::AllFonts) { } void _k_slotFontChanged(const QFont &font) { // qCDebug(KWidgetsAddonsLog) << "QFontComboBox - slotFontChanged(" // << font.family() << ") settingFont=" << settingFont; if (settingFont) { return; } q->setFont(font.family()); emit q->triggered(font.family()); // qCDebug(KWidgetsAddonsLog) << "\tslotFontChanged done"; } KFontAction *q; int settingFont; QFontComboBox::FontFilters fontFilters; }; QStringList _k_fontList(const QFontComboBox::FontFilters &fontFilters = QFontComboBox::AllFonts) { QFontDatabase dbase; QStringList families; if (fontFilters == QFontComboBox::AllFonts) { families = dbase.families(); } else { const QFontComboBox::FontFilters scalableMask = (QFontComboBox::ScalableFonts | QFontComboBox::NonScalableFonts); const QFontComboBox::FontFilters spacingMask = (QFontComboBox::ProportionalFonts | QFontComboBox::MonospacedFonts); foreach (const QString &family, dbase.families()) { if ((fontFilters & scalableMask) && (fontFilters & scalableMask) != scalableMask) { if (bool(fontFilters & QFontComboBox::ScalableFonts) != dbase.isSmoothlyScalable(family)) { continue; } } if ((fontFilters & spacingMask) && (fontFilters & spacingMask) != spacingMask) { if (bool(fontFilters & QFontComboBox::MonospacedFonts) != dbase.isFixedPitch(family)) { continue; } } families << family; } } families.sort(); return families; } KFontAction::KFontAction(uint fontListCriteria, QObject *parent) : KSelectAction(parent), d(new KFontActionPrivate(this)) { if (fontListCriteria & KFontChooser::FixedWidthFonts) { d->fontFilters |= QFontComboBox::MonospacedFonts; } if (fontListCriteria & KFontChooser::SmoothScalableFonts) { d->fontFilters |= QFontComboBox::ScalableFonts; } KSelectAction::setItems(_k_fontList(d->fontFilters)); setEditable(true); } KFontAction::KFontAction(QObject *parent) : KSelectAction(parent), d(new KFontActionPrivate(this)) { KSelectAction::setItems(_k_fontList()); setEditable(true); } KFontAction::KFontAction(const QString &text, QObject *parent) : KSelectAction(text, parent), d(new KFontActionPrivate(this)) { KSelectAction::setItems(_k_fontList()); setEditable(true); } KFontAction::KFontAction(const QIcon &icon, const QString &text, QObject *parent) : KSelectAction(icon, text, parent), d(new KFontActionPrivate(this)) { KSelectAction::setItems(_k_fontList()); setEditable(true); } KFontAction::~KFontAction() { delete d; } QString KFontAction::font() const { return currentText(); } QWidget *KFontAction::createWidget(QWidget *parent) { // qCDebug(KWidgetsAddonsLog) << "KFontAction::createWidget()"; #ifdef __GNUC__ #warning FIXME: items need to be converted #endif // This is the visual element on the screen. This method overrides // the KSelectAction one, preventing KSelectAction from creating its // regular KComboBox. QFontComboBox *cb = new QFontComboBox(parent); cb->setFontFilters(d->fontFilters); // qCDebug(KWidgetsAddonsLog) << "\tset=" << font(); // Do this before connecting the signal so that nothing will fire. cb->setCurrentFont(QFont(font().toLower())); // qCDebug(KWidgetsAddonsLog) << "\tspit back=" << cb->currentFont().family(); connect(cb, &QFontComboBox::currentFontChanged, this, [this](const QFont &ft) { d->_k_slotFontChanged(ft); }); cb->setMinimumWidth(cb->sizeHint().width()); return cb; } /* * Maintenance note: Keep in sync with QFontComboBox::setCurrentFont() */ void KFontAction::setFont(const QString &family) { // qCDebug(KWidgetsAddonsLog) << "KFontAction::setFont(" << family << ")"; // Suppress triggered(QString) signal and prevent recursive call to ourself. d->settingFont++; foreach (QWidget *w, createdWidgets()) { QFontComboBox *cb = qobject_cast(w); // qCDebug(KWidgetsAddonsLog) << "\tw=" << w << "cb=" << cb; if (!cb) { continue; } cb->setCurrentFont(QFont(family.toLower())); // qCDebug(KWidgetsAddonsLog) << "\t\tw spit back=" << cb->currentFont().family(); } d->settingFont--; // qCDebug(KWidgetsAddonsLog) << "\tcalling setCurrentAction()"; QString lowerName = family.toLower(); if (setCurrentAction(lowerName, Qt::CaseInsensitive)) { return; } int i = lowerName.indexOf(QStringLiteral(" [")); if (i > -1) { lowerName = lowerName.left(i); i = 0; if (setCurrentAction(lowerName, Qt::CaseInsensitive)) { return; } } lowerName += QStringLiteral(" ["); if (setCurrentAction(lowerName, Qt::CaseInsensitive)) { return; } // TODO: Inconsistent state if QFontComboBox::setCurrentFont() succeeded // but setCurrentAction() did not and vice-versa. // qCDebug(KWidgetsAddonsLog) << "Font not found " << family.toLower(); } #include "moc_kfontaction.cpp" diff --git a/src/kfontrequester.cpp b/src/kfontrequester.cpp index 47783e3..754f1d5 100644 --- a/src/kfontrequester.cpp +++ b/src/kfontrequester.cpp @@ -1,237 +1,236 @@ /* Copyright (C) 2003 Nadeem Hasan This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kfontrequester.h" #include "fonthelpers_p.h" #include #include -#include #include #include #include -#include +#include #include #include // Determine if the font with given properties is available on the system, // otherwise find and return the best fitting combination. static QFont nearestExistingFont(const QFont &font) { QFontDatabase dbase; // Initialize font data according to given font object. QString family = font.family(); QString style = dbase.styleString(font); qreal size = font.pointSizeF(); // Check if the family exists. const QStringList families = dbase.families(); if (!families.contains(family)) { // Chose another family. family = QFontInfo(font).family(); // the nearest match if (!families.contains(family)) { family = families.count() ? families.at(0) : QStringLiteral("fixed"); } } // Check if the family has the requested style. // Easiest by piping it through font selection in the database. QString retStyle = dbase.styleString(dbase.font(family, style, 10)); style = retStyle; // Check if the family has the requested size. // Only for bitmap fonts. if (!dbase.isSmoothlyScalable(family, style)) { QList sizes = dbase.smoothSizes(family, style); if (!sizes.contains(size)) { // Find nearest available size. int mindiff = 1000; int refsize = size; Q_FOREACH (int lsize, sizes) { int diff = qAbs(refsize - lsize); if (mindiff > diff) { mindiff = diff; size = lsize; } } } } // Select the font with confirmed properties. QFont result = dbase.font(family, style, int(size)); if (dbase.isSmoothlyScalable(family, style) && result.pointSize() == floor(size)) { result.setPointSizeF(size); } return result; } class Q_DECL_HIDDEN KFontRequester::KFontRequesterPrivate { public: KFontRequesterPrivate(KFontRequester *q): q(q) {} void displaySampleText(); void setToolTip(); void _k_buttonClicked(); KFontRequester *q; bool m_onlyFixed; QString m_sampleText, m_title; QLabel *m_sampleLabel = nullptr; QPushButton *m_button = nullptr; QFont m_selFont; }; KFontRequester::KFontRequester(QWidget *parent, bool onlyFixed) : QWidget(parent), d(new KFontRequesterPrivate(this)) { d->m_onlyFixed = onlyFixed; QHBoxLayout *layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); d->m_sampleLabel = new QLabel(this); d->m_button = new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit")), QStringLiteral(), this); d->m_sampleLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); setFocusProxy(d->m_button); setFocusPolicy(d->m_button->focusPolicy()); layout->addWidget(d->m_sampleLabel, 1); layout->addWidget(d->m_button); connect(d->m_button, &QPushButton::clicked, this, [this] { d->_k_buttonClicked(); }); d->displaySampleText(); d->setToolTip(); } KFontRequester::~KFontRequester() { delete d; } QFont KFontRequester::font() const { return d->m_selFont; } bool KFontRequester::isFixedOnly() const { return d->m_onlyFixed; } QString KFontRequester::sampleText() const { return d->m_sampleText; } QString KFontRequester::title() const { return d->m_title; } QLabel *KFontRequester::label() const { return d->m_sampleLabel; } QPushButton *KFontRequester::button() const { return d->m_button; } void KFontRequester::setFont(const QFont &font, bool onlyFixed) { d->m_selFont = nearestExistingFont(font); d->m_onlyFixed = onlyFixed; d->displaySampleText(); emit fontSelected(d->m_selFont); } void KFontRequester::setSampleText(const QString &text) { d->m_sampleText = text; d->displaySampleText(); } void KFontRequester::setTitle(const QString &title) { d->m_title = title; d->setToolTip(); } void KFontRequester::KFontRequesterPrivate::_k_buttonClicked() { QFontDialog::FontDialogOptions flags; if (m_onlyFixed) { flags = QFontDialog::MonospacedFonts; } bool ok = false; QFont font = QFontDialog::getFont(&ok, m_selFont, q->parentWidget(), QString(), flags); if (ok) { m_selFont = font; displaySampleText(); emit q->fontSelected(m_selFont); } } void KFontRequester::KFontRequesterPrivate::displaySampleText() { m_sampleLabel->setFont(m_selFont); qreal size = m_selFont.pointSizeF(); if (size == -1) { size = m_selFont.pixelSize(); } if (m_sampleText.isEmpty()) { QString family = translateFontName(m_selFont.family()); m_sampleLabel->setText(QStringLiteral("%1 %2").arg(family).arg(size)); } else { m_sampleLabel->setText(m_sampleText); } } void KFontRequester::KFontRequesterPrivate::setToolTip() { m_button->setToolTip(tr("Choose Font...")); m_sampleLabel->setToolTip(QString()); m_sampleLabel->setWhatsThis(QString()); if (m_title.isNull()) { m_sampleLabel->setToolTip(tr("Preview of the selected font")); m_sampleLabel->setWhatsThis(tr("This is a preview of the selected font. You can change it" " by clicking the \"Choose Font...\" button.")); } else { m_sampleLabel->setToolTip(tr("Preview of the \"%1\" font").arg(m_title)); m_sampleLabel->setWhatsThis(tr("This is a preview of the \"%1\" font. You can change it" " by clicking the \"Choose Font...\" button.").arg(m_title)); } } #include "moc_kfontrequester.cpp" diff --git a/src/kfontsizeaction.cpp b/src/kfontsizeaction.cpp index e3dc4d2..4db264c 100644 --- a/src/kfontsizeaction.cpp +++ b/src/kfontsizeaction.cpp @@ -1,143 +1,140 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2002 Joseph Wenninger (C) 2003 Andras Mantia (C) 2005-2006 Hamish Rodda This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kfontsizeaction.h" #include "loggingcategory.h" -#include #include -#include -#include class Q_DECL_HIDDEN KFontSizeAction::Private { public: Private(KFontSizeAction *parent) : q(parent) { } void init(); KFontSizeAction *q; }; // BEGIN KFontSizeAction KFontSizeAction::KFontSizeAction(QObject *parent) : KSelectAction(parent), d(new Private(this)) { d->init(); } KFontSizeAction::KFontSizeAction(const QString &text, QObject *parent) : KSelectAction(text, parent), d(new Private(this)) { d->init(); } KFontSizeAction::KFontSizeAction(const QIcon &icon, const QString &text, QObject *parent) : KSelectAction(icon, text, parent), d(new Private(this)) { d->init(); } KFontSizeAction::~KFontSizeAction() { delete d; } void KFontSizeAction::Private::init() { q->setEditable(true); QFontDatabase fontDB; const QList sizes = fontDB.standardSizes(); QStringList lst; lst.reserve(sizes.count()); for (QList::ConstIterator it = sizes.begin(), total = sizes.end(); it != total; ++it) { lst.append(QString::number(*it)); } q->setItems(lst); } void KFontSizeAction::setFontSize(int size) { if (size == fontSize()) { const QString test = QString::number(size); Q_FOREACH (QAction *action, actions()) { if (action->text() == test) { setCurrentAction(action); return; } } } if (size < 1) { qCWarning(KWidgetsAddonsLog) << "KFontSizeAction: Size " << size << " is out of range"; return; } QAction *a = action(QString::number(size)); if (!a) { // Insert at the correct position in the list (to keep sorting) QList lst; // Convert to list of ints QStringListIterator itemsIt(items()); while (itemsIt.hasNext()) { lst.append(itemsIt.next().toInt()); } // New size lst.append(size); // Sort the list std::sort(lst.begin(), lst.end()); for (int it : qAsConst(lst)) { QAction *const action = addAction(QString::number(it)); if (it == size) { setCurrentAction(action); } } } else { setCurrentAction(a); } } int KFontSizeAction::fontSize() const { return currentText().toInt(); } void KFontSizeAction::actionTriggered(QAction *action) { emit fontSizeChanged(action->text().toInt()); KSelectAction::actionTriggered(action); } diff --git a/src/kled.cpp b/src/kled.cpp index 16ed829..4810fd2 100644 --- a/src/kled.cpp +++ b/src/kled.cpp @@ -1,283 +1,282 @@ /* This file is part of the KDE libraries Copyright (C) 1998 Jörg Habenicht (j.habenicht@europemail.com) Copyright (C) 2010 Christoph Feck This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kled.h" -#include #include #include #include #include class Q_DECL_HIDDEN KLed::Private { public: Private() : darkFactor(300), state(On), look(Raised), shape(Circular) { } int darkFactor; QColor color; State state; Look look; Shape shape; QPixmap cachedPixmap[2]; // for both states }; KLed::KLed(QWidget *parent) : QWidget(parent), d(new Private) { setColor(Qt::green); updateAccessibleName(); } KLed::KLed(const QColor &color, QWidget *parent) : QWidget(parent), d(new Private) { setColor(color); updateAccessibleName(); } KLed::KLed(const QColor &color, State state, Look look, Shape shape, QWidget *parent) : QWidget(parent), d(new Private) { d->state = (state == Off ? Off : On); d->look = look; d->shape = shape; setColor(color); updateAccessibleName(); } KLed::~KLed() { delete d; } KLed::State KLed::state() const { return d->state; } KLed::Shape KLed::shape() const { return d->shape; } QColor KLed::color() const { return d->color; } KLed::Look KLed::look() const { return d->look; } void KLed::setState(State state) { if (d->state == state) { return; } d->state = (state == Off ? Off : On); updateCachedPixmap(); updateAccessibleName(); } void KLed::setShape(Shape shape) { if (d->shape == shape) { return; } d->shape = shape; updateCachedPixmap(); } void KLed::setColor(const QColor &color) { if (d->color == color) { return; } d->color = color; updateCachedPixmap(); } void KLed::setDarkFactor(int darkFactor) { if (d->darkFactor == darkFactor) { return; } d->darkFactor = darkFactor; updateCachedPixmap(); } int KLed::darkFactor() const { return d->darkFactor; } void KLed::setLook(Look look) { if (d->look == look) { return; } d->look = look; updateCachedPixmap(); } void KLed::toggle() { d->state = (d->state == On ? Off : On); updateCachedPixmap(); updateAccessibleName(); } void KLed::on() { setState(On); } void KLed::off() { setState(Off); } void KLed::resizeEvent(QResizeEvent *) { updateCachedPixmap(); } QSize KLed::sizeHint() const { QStyleOption option; option.initFrom(this); int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, &option, this); return QSize(iconSize, iconSize); } QSize KLed::minimumSizeHint() const { return QSize(16, 16); } void KLed::updateAccessibleName() { #ifndef QT_NO_ACCESSIBILITY QString onName = tr("LED on", "Accessible name of a Led whose state is on"); QString offName = tr("LED off", "Accessible name of a Led whose state is off"); QString lastName = accessibleName(); if (lastName.isEmpty() || lastName == onName || lastName == offName) { //Accessible name has not been manually set. setAccessibleName(d->state == On ? onName : offName); } #endif } void KLed::updateCachedPixmap() { d->cachedPixmap[Off] = QPixmap(); d->cachedPixmap[On] = QPixmap(); update(); } void KLed::paintEvent(QPaintEvent *) { if (!d->cachedPixmap[d->state].isNull()) { QPainter painter(this); painter.drawPixmap(1, 1, d->cachedPixmap[d->state]); return; } QSize size(width() - 2, height() - 2); if (d->shape == Circular) { // Make sure the LED is round const int dim = qMin(width(), height()) - 2; size = QSize(dim, dim); } QPointF center(size.width() / 2.0, size.height() / 2.0); const int smallestSize = qMin(size.width(), size.height()); QPainter painter; QImage image(size, QImage::Format_ARGB32_Premultiplied); image.fill(0); QRadialGradient fillGradient(center, smallestSize / 2.0, QPointF(center.x(), size.height() / 3.0)); const QColor fillColor = d->state != Off ? d->color : d->color.darker(d->darkFactor); fillGradient.setColorAt(0.0, fillColor.lighter(250)); fillGradient.setColorAt(0.5, fillColor.lighter(130)); fillGradient.setColorAt(1.0, fillColor); QConicalGradient borderGradient(center, d->look == Sunken ? 90 : -90); QColor borderColor = palette().color(QPalette::Dark); if (d->state == On) { QColor glowOverlay = fillColor; glowOverlay.setAlpha(80); // This isn't the fastest way, but should be "fast enough". // It's also the only safe way to use QPainter::CompositionMode QImage img(1, 1, QImage::Format_ARGB32_Premultiplied); QPainter p(&img); QColor start = borderColor; start.setAlpha(255); // opaque p.fillRect(0, 0, 1, 1, start); p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.fillRect(0, 0, 1, 1, glowOverlay); p.end(); borderColor = img.pixel(0, 0); } borderGradient.setColorAt(0.2, borderColor); borderGradient.setColorAt(0.5, palette().color(QPalette::Light)); borderGradient.setColorAt(0.8, borderColor); painter.begin(&image); painter.setRenderHint(QPainter::Antialiasing); painter.setBrush(d->look == Flat ? QBrush(fillColor) : QBrush(fillGradient)); const QBrush penBrush = (d->look == Flat) ? QBrush(borderColor) : QBrush(borderGradient); const qreal penWidth = smallestSize / 8.0; painter.setPen(QPen(penBrush, penWidth)); QRectF r(penWidth / 2.0, penWidth / 2.0, size.width() - penWidth, size.height() - penWidth); if (d->shape == Rectangular) { painter.drawRect(r); } else { painter.drawEllipse(r); } painter.end(); d->cachedPixmap[d->state] = QPixmap::fromImage(image); painter.begin(this); painter.drawPixmap(1, 1, d->cachedPixmap[d->state]); painter.end(); } diff --git a/src/kmessagebox.cpp b/src/kmessagebox.cpp index e9d8a7f..c9c1df2 100644 --- a/src/kmessagebox.cpp +++ b/src/kmessagebox.cpp @@ -1,1150 +1,1148 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Waldo Bastian (bastian@kde.org) Copyright 2012 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; version 2 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kmessagebox.h" #include "kmessagebox_p.h" #include #include #include #include -#include #include #include #include #include #include #include #include -#include #include #include #include #if 0 // NOTE waiting for the notification framework plan #include #endif #include #include // Some i18n filters, that standard button texts are piped through // (the new KGuiItem object with filtered text is created from the old one). // Filter for the Yes-button text in standard message dialogs, // after the message caption/text have been translated. #define I18N_FILTER_BUTTON_YES(src, dst) \ KGuiItem dst(src); \ dst.setText( QApplication::translate( "KMessageBox", src.text().toUtf8().constData(), "@action:button filter-yes" ) ); // Filter for the No-button text in standard message dialogs, // after the message caption/text have been translated. #define I18N_FILTER_BUTTON_NO(src, dst) \ KGuiItem dst(src); \ dst.setText( QApplication::translate( "KMessageBox", src.text().toUtf8().constData(), "@action:button filter-no" ) ); // Filter for the Continue-button text in standard message dialogs, // after the message caption/text have been translated. #define I18N_FILTER_BUTTON_CONTINUE(src, dst) \ KGuiItem dst(src); \ dst.setText( QApplication::translate( "KMessageBox", src.text().toUtf8().constData(), "@action:button filter-continue" ) ); // Filter for the Cancel-button text in standard message dialogs, // after the message caption/text have been translated. #define I18N_FILTER_BUTTON_CANCEL(src, dst) \ KGuiItem dst(src); \ dst.setText( QApplication::translate( "KMessageBox", src.text().toUtf8().constData(), "@action:button filter-cancel" ) ); // Called after the button texts in standard message dialogs // have been filtered by the messages above. Not visible to user. #define I18N_POST_BUTTON_FILTER \ QApplication::translate( "KMessageBox", ".", "@action:button post-filter" ); namespace KMessageBox { /* * this static is used by the createKMessageBox function to enqueue dialogs * FIXME what should we do about this static? */ QDialogButtonBox::StandardButton KWIDGETSADDONS_EXPORT(*KMessageBox_exec_hook)(QDialog *) = nullptr; static void applyOptions(QDialog *dialog, KMessageBox::Options options) { if (options & KMessageBox::WindowModal) { dialog->setWindowModality(Qt::WindowModal); } dialog->setModal(true); } // This method has been copied from KWindowSystem to avoid depending on it static void setMainWindow(QWidget *subWidget, WId mainWindowId) { #ifdef Q_OS_OSX if (!QWidget::find(mainWindowId)) { return; } #endif // Set the WA_NativeWindow attribute to force the creation of the QWindow. // Without this QWidget::windowHandle() returns 0. subWidget->setAttribute(Qt::WA_NativeWindow, true); QWindow *subWindow = subWidget->windowHandle(); Q_ASSERT(subWindow); QWindow *mainWindow = QWindow::fromWinId(mainWindowId); if (!mainWindow) { // foreign windows not supported on all platforms return; } // mainWindow is not the child of any object, so make sure it gets deleted at some point QObject::connect(subWidget, &QObject::destroyed, mainWindow, &QObject::deleteLater); subWindow->setTransientParent(mainWindow); } /** * Create a QDialog whose parent is a foreign window */ static QDialog *createWIdDialog(WId parent_id) { QWidget *parent = QWidget::find(parent_id); QDialog *dialog = new QDialog(parent, Qt::Dialog); if (!parent && parent_id) { setMainWindow(dialog, parent_id); } return dialog; } class DialogButtonsHelper : public QObject { Q_OBJECT public: DialogButtonsHelper(QDialog *dialog, QDialogButtonBox *buttons) : QObject(dialog), m_dialog(dialog), m_buttons(buttons), m_details(nullptr) { connect(m_buttons, &QDialogButtonBox::clicked, this, &DialogButtonsHelper::onButtonClicked); } void setDetailsWidget(QWidget *widget) { m_details = widget; } public Q_SLOTS: void onButtonClicked(QAbstractButton *button) { QDialogButtonBox::StandardButton code = m_buttons->standardButton(button); if (code != QDialogButtonBox::NoButton) { m_dialog->done(code); } } private: QDialog *const m_dialog; QDialogButtonBox *const m_buttons; QWidget *m_details; }; QDialogButtonBox::StandardButton createKMessageBox(QDialog *dialog, QDialogButtonBox *buttons, QMessageBox::Icon icon, const QString &text, const QStringList &strlist, const QString &ask, bool *checkboxReturn, Options options, const QString &details) { QIcon tmpIcon; QStyle *style = dialog ? dialog->style() : QApplication::style(); switch (icon) { case QMessageBox::Information: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, dialog); break; case QMessageBox::Warning: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, dialog); break; case QMessageBox::Critical: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, nullptr, dialog); break; case QMessageBox::Question: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, dialog); break; default: break; } return createKMessageBox(dialog, buttons, tmpIcon, text, strlist, ask, checkboxReturn, options, details, icon); } QDialogButtonBox::StandardButton createKMessageBox(QDialog *dialog, QDialogButtonBox *buttons, const QIcon &icon, const QString &text, const QStringList &strlist, const QString &ask, bool *checkboxReturn, Options options, const QString &details, QMessageBox::Icon notifyType) { DialogButtonsHelper *buttonsHelper = new DialogButtonsHelper(dialog, buttons); QWidget *mainWidget = new QWidget(dialog); QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget); const int spacingHint = mainWidget->style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); mainLayout->setSpacing(spacingHint * 2); // provide extra spacing mainLayout->setContentsMargins(0, 0, 0, 0); buttons->setParent(dialog); QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->setContentsMargins(0, 0, 0, 0); hLayout->setSpacing(-1); // use default spacing mainLayout->addLayout(hLayout, 5); QLabel *iconLabel = new QLabel(mainWidget); if (!icon.isNull()) { QStyleOption option; option.initFrom(mainWidget); iconLabel->setPixmap(icon.pixmap(mainWidget->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, mainWidget))); } QVBoxLayout *iconLayout = new QVBoxLayout(); iconLayout->addStretch(1); iconLayout->addWidget(iconLabel); iconLayout->addStretch(5); hLayout->addLayout(iconLayout, 0); hLayout->addSpacing(spacingHint); QLabel *messageLabel = new QLabel(text, mainWidget); messageLabel->setOpenExternalLinks(options & KMessageBox::AllowLink); Qt::TextInteractionFlags flags = Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard; if (options & KMessageBox::AllowLink) { flags |= Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard; } messageLabel->setTextInteractionFlags(flags); QRect desktop = QApplication::desktop()->screenGeometry(dialog); bool usingSqueezedTextLabel = false; if (messageLabel->sizeHint().width() > desktop.width() * 0.5) { // enable automatic wrapping of messages which are longer than 50% of screen width messageLabel->setWordWrap(true); // use a squeezed label if text is still too wide usingSqueezedTextLabel = messageLabel->sizeHint().width() > desktop.width() * 0.85; if (usingSqueezedTextLabel) { delete messageLabel; messageLabel = new KSqueezedTextLabel(text, mainWidget); messageLabel->setOpenExternalLinks(options & KMessageBox::AllowLink); messageLabel->setTextInteractionFlags(flags); } } QPalette messagePal(messageLabel->palette()); messagePal.setColor(QPalette::Window, Qt::transparent); messageLabel->setPalette(messagePal); bool usingScrollArea = desktop.height() / 3 < messageLabel->sizeHint().height(); if (usingScrollArea) { QScrollArea *messageScrollArea = new QScrollArea(mainWidget); messageScrollArea->setWidget(messageLabel); messageScrollArea->setFrameShape(QFrame::NoFrame); messageScrollArea->setWidgetResizable(true); QPalette scrollPal(messageScrollArea->palette()); scrollPal.setColor(QPalette::Window, Qt::transparent); messageScrollArea->viewport()->setPalette(scrollPal); hLayout->addWidget(messageScrollArea, 5); } else { hLayout->addWidget(messageLabel, 5); } const bool usingListWidget = !strlist.isEmpty(); if (usingListWidget) { // enable automatic wrapping since the listwidget has already a good initial width messageLabel->setWordWrap(true); QListWidget *listWidget = new QListWidget(mainWidget); listWidget->addItems(strlist); QStyleOptionViewItem styleOption; styleOption.initFrom(listWidget); QFontMetrics fm(styleOption.font); int w = listWidget->width(); for (const QString &str : strlist) { w = qMax(w, fm.width(str)); } const int borderWidth = listWidget->width() - listWidget->viewport()->width() + listWidget->verticalScrollBar()->height(); w += borderWidth; if (w > desktop.width() * 0.85) { // limit listWidget size to 85% of screen width w = qRound(desktop.width() * 0.85); } listWidget->setMinimumWidth(w); mainLayout->addWidget(listWidget, usingScrollArea ? 10 : 50); listWidget->setSelectionMode(QListWidget::NoSelection); messageLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); } else if (!usingScrollArea) { mainLayout->addStretch(15); } QPointer checkbox = nullptr; if (!ask.isEmpty()) { checkbox = new QCheckBox(ask, mainWidget); mainLayout->addWidget(checkbox); if (checkboxReturn) { checkbox->setChecked(*checkboxReturn); } } QVBoxLayout *topLayout = new QVBoxLayout; dialog->setLayout(topLayout); topLayout->addWidget(mainWidget); if (!details.isEmpty()) { QHBoxLayout *detailsHLayout = new QHBoxLayout(); detailsHLayout->addSpacing(2 * spacingHint + iconLayout->sizeHint().width()); KCollapsibleGroupBox *detailsGroup = new KCollapsibleGroupBox(); detailsGroup->setTitle(QApplication::translate("KMessageBox", "Details")); QVBoxLayout *detailsLayout = new QVBoxLayout(detailsGroup); if (details.length() < 512) { QLabel *detailsLabel = new QLabel(details); detailsLabel->setOpenExternalLinks(options & KMessageBox::AllowLink); Qt::TextInteractionFlags flags = Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard; if (options & KMessageBox::AllowLink) { flags |= Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard; }; detailsLabel->setTextInteractionFlags(flags); detailsLabel->setWordWrap(true); detailsLabel->setMinimumSize(detailsLabel->sizeHint()); detailsLayout->addWidget(detailsLabel, 50); } else { QTextBrowser *detailTextEdit = new QTextBrowser(); detailTextEdit->setText(details); detailTextEdit->setReadOnly(true); detailTextEdit->setMinimumHeight(detailTextEdit->fontMetrics().lineSpacing() * 11); detailsLayout->addWidget(detailTextEdit, 50); } if (!usingListWidget) { mainLayout->setStretchFactor(hLayout, 10); } detailsHLayout->addWidget(detailsGroup); topLayout->addLayout(detailsHLayout); buttonsHelper->setDetailsWidget(detailsGroup); } topLayout->addWidget(buttons); topLayout->setSizeConstraint(QLayout::SetFixedSize); if (!usingListWidget && !usingScrollArea && !usingSqueezedTextLabel && details.isEmpty()) { dialog->setFixedSize(dialog->sizeHint() + QSize(10, 10)); } if ((options & KMessageBox::Dangerous)) { QPushButton *cancelButton = buttons->button(QDialogButtonBox::Cancel); QPushButton *noButton = buttons->button(QDialogButtonBox::No); if (cancelButton && cancelButton->isEnabled()) { cancelButton->setDefault(true); cancelButton->setFocus(); } else if (noButton && noButton->isEnabled()) { noButton->setDefault(true); noButton->setFocus(); } } #ifndef Q_OS_WIN // FIXME problems with KNotify on Windows if ((options & KMessageBox::Notify)) { QString message = text; if (!strlist.isEmpty()) { message += QLatin1Char('\n') + strlist.join(QLatin1Char('\n')); } notifyInterface()->sendNotification(notifyType, message, dialog->topLevelWidget()); } #endif if (KMessageBox_exec_hook) { return KMessageBox_exec_hook(dialog); } if ((options & KMessageBox::NoExec)) { return QDialogButtonBox::NoButton; // We have to return something. } // We use a QPointer because the dialog may get deleted // during exec() if the parent of the dialog gets deleted. // In that case the QPointer will reset to 0. QPointer guardedDialog = dialog; const QDialogButtonBox::StandardButton result = QDialogButtonBox::StandardButton(guardedDialog->exec()); if (checkbox && checkboxReturn) { *checkboxReturn = checkbox->isChecked(); } delete guardedDialog; return result; } ButtonCode questionYesNo(QWidget *parent, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return questionYesNoList(parent, text, QStringList(), caption, buttonYes, buttonNo, dontAskAgainName, options); } bool shouldBeShownYesNo(const QString &dontShowAgainName, ButtonCode &result) { if (dontShowAgainName.isEmpty()) { return true; } return dontAskAgainInterface()->shouldBeShownYesNo(dontShowAgainName, result); } bool shouldBeShownContinue(const QString &dontShowAgainName) { if (dontShowAgainName.isEmpty()) { return true; } return dontAskAgainInterface()->shouldBeShownContinue(dontShowAgainName); } void saveDontShowAgainYesNo(const QString &dontShowAgainName, ButtonCode result) { if (dontShowAgainName.isEmpty()) { return; } dontAskAgainInterface()->saveDontShowAgainYesNo(dontShowAgainName, result); } void saveDontShowAgainContinue(const QString &dontShowAgainName) { if (dontShowAgainName.isEmpty()) { return; } dontAskAgainInterface()->saveDontShowAgainContinue(dontShowAgainName); } void enableAllMessages() { dontAskAgainInterface()->enableAllMessages(); } void enableMessage(const QString &dontShowAgainName) { dontAskAgainInterface()->enableMessage(dontShowAgainName); } void setDontShowAgainConfig(KConfig *cfg) { dontAskAgainInterface()->setConfig(cfg); } static ButtonCode questionYesNoListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes_, const KGuiItem &buttonNo_, const QString &dontAskAgainName, Options options) { ButtonCode res; if (!shouldBeShownYesNo(dontAskAgainName, res)) { delete dialog; return res; } I18N_FILTER_BUTTON_YES(buttonYes_, buttonYes) I18N_FILTER_BUTTON_NO(buttonNo_, buttonNo) I18N_POST_BUTTON_FILTER dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Question") : caption); dialog->setObjectName(QStringLiteral("questionYesNo")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), buttonYes); KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), buttonNo); applyOptions(dialog, options); bool checkboxResult = false; const int result = createKMessageBox(dialog, buttonBox, QMessageBox::Question, text, strlist, dontAskAgainName.isEmpty() ? QString() : QApplication::translate("KMessageBox", "Do not ask again"), &checkboxResult, options); res = (result == QDialogButtonBox::Yes ? Yes : No); if (checkboxResult) { saveDontShowAgainYesNo(dontAskAgainName, res); } return res; } ButtonCode questionYesNoList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return questionYesNoListInternal(new QDialog(parent), text, strlist, caption, buttonYes, buttonNo, dontAskAgainName, options); } static ButtonCode questionYesNoCancelInternal(QDialog *dialog, const QString &text, const QString &caption, const KGuiItem &buttonYes_, const KGuiItem &buttonNo_, const KGuiItem &buttonCancel_, const QString &dontAskAgainName, Options options) { ButtonCode res; if (!shouldBeShownYesNo(dontAskAgainName, res)) { delete dialog; return res; } I18N_FILTER_BUTTON_YES(buttonYes_, buttonYes) I18N_FILTER_BUTTON_NO(buttonNo_, buttonNo) I18N_FILTER_BUTTON_CANCEL(buttonCancel_, buttonCancel) I18N_POST_BUTTON_FILTER dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Question") : caption); dialog->setObjectName(QStringLiteral("questionYesNoCancel")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), buttonYes); KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), buttonNo); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), buttonCancel); applyOptions(dialog, options); bool checkboxResult = false; const int result = createKMessageBox(dialog, buttonBox, QMessageBox::Question, text, QStringList(), dontAskAgainName.isEmpty() ? QString() : QApplication::translate("KMessageBox", "Do not ask again"), &checkboxResult, options); if (result == QDialogButtonBox::Yes) { res = Yes; } else if (result == QDialogButtonBox::No) { res = No; } else { return Cancel; } if (checkboxResult) { saveDontShowAgainYesNo(dontAskAgainName, res); } return res; } ButtonCode questionYesNoCancel(QWidget *parent, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return questionYesNoCancelInternal(new QDialog(parent), text, caption, buttonYes, buttonNo, buttonCancel, dontAskAgainName, options); } ButtonCode warningYesNo(QWidget *parent, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return warningYesNoList(parent, text, QStringList(), caption, buttonYes, buttonNo, dontAskAgainName, options); } static ButtonCode warningYesNoListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes_, const KGuiItem &buttonNo_, const QString &dontAskAgainName, Options options) { ButtonCode res; if (!shouldBeShownYesNo(dontAskAgainName, res)) { delete dialog; return res; } I18N_FILTER_BUTTON_YES(buttonYes_, buttonYes) I18N_FILTER_BUTTON_NO(buttonNo_, buttonNo) I18N_POST_BUTTON_FILTER dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Warning") : caption); dialog->setObjectName(QStringLiteral("warningYesNoList")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), buttonYes); KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), buttonNo); applyOptions(dialog, options); bool checkboxResult = false; const int result = createKMessageBox(dialog, buttonBox, QMessageBox::Warning, text, strlist, dontAskAgainName.isEmpty() ? QString() : QApplication::translate("KMessageBox", "Do not ask again"), &checkboxResult, options); res = (result == QDialogButtonBox::Yes ? Yes : No); if (checkboxResult) { saveDontShowAgainYesNo(dontAskAgainName, res); } return res; } ButtonCode warningYesNoList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return warningYesNoListInternal(new QDialog(parent), text, strlist, caption, buttonYes, buttonNo, dontAskAgainName, options); } ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &caption, const KGuiItem &buttonContinue, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningContinueCancelList(parent, text, QStringList(), caption, buttonContinue, buttonCancel, dontAskAgainName, options); } static ButtonCode warningContinueCancelListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonContinue_, const KGuiItem &buttonCancel_, const QString &dontAskAgainName, Options options) { if (!shouldBeShownContinue(dontAskAgainName)) { delete dialog; return Continue; } I18N_FILTER_BUTTON_CONTINUE(buttonContinue_, buttonContinue) I18N_FILTER_BUTTON_CANCEL(buttonCancel_, buttonCancel) I18N_POST_BUTTON_FILTER dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Warning") : caption); dialog->setObjectName(QStringLiteral("warningYesNo")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), buttonContinue); KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), buttonCancel); applyOptions(dialog, options); bool checkboxResult = false; const int result = createKMessageBox(dialog, buttonBox, QMessageBox::Warning, text, strlist, dontAskAgainName.isEmpty() ? QString() : QApplication::translate("KMessageBox", "Do not ask again"), &checkboxResult, options); if (result != QDialogButtonBox::Yes) { return Cancel; } if (checkboxResult) { saveDontShowAgainContinue(dontAskAgainName); } return Continue; } ButtonCode warningContinueCancelList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonContinue, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningContinueCancelListInternal(new QDialog(parent), text, strlist, caption, buttonContinue, buttonCancel, dontAskAgainName, options); } ButtonCode warningYesNoCancel(QWidget *parent, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningYesNoCancelList(parent, text, QStringList(), caption, buttonYes, buttonNo, buttonCancel, dontAskAgainName, options); } static ButtonCode warningYesNoCancelListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes_, const KGuiItem &buttonNo_, const KGuiItem &buttonCancel_, const QString &dontAskAgainName, Options options) { ButtonCode res; if (!shouldBeShownYesNo(dontAskAgainName, res)) { delete dialog; return res; } I18N_FILTER_BUTTON_YES(buttonYes_, buttonYes) I18N_FILTER_BUTTON_NO(buttonNo_, buttonNo) I18N_FILTER_BUTTON_CANCEL(buttonCancel_, buttonCancel) I18N_POST_BUTTON_FILTER dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Warning") : caption); dialog->setObjectName(QStringLiteral("warningYesNoCancel")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), buttonYes); KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), buttonNo); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), buttonCancel); applyOptions(dialog, options); bool checkboxResult = false; const int result = createKMessageBox(dialog, buttonBox, QMessageBox::Warning, text, strlist, dontAskAgainName.isEmpty() ? QString() : QApplication::translate("KMessageBox", "Do not ask again"), &checkboxResult, options); if (result == QDialogButtonBox::Yes) { res = Yes; } else if (result == QDialogButtonBox::No) { res = No; } else { return Cancel; } if (checkboxResult) { saveDontShowAgainYesNo(dontAskAgainName, res); } return res; } ButtonCode warningYesNoCancelList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningYesNoCancelListInternal(new QDialog(parent), text, strlist, caption, buttonYes, buttonNo, buttonCancel, dontAskAgainName, options); } void error(QWidget *parent, const QString &text, const QString &caption, Options options) { errorList(parent, text, QStringList(), caption, options); } static void errorListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &caption, Options options) { dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Error") : caption); dialog->setObjectName(QStringLiteral("error")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok); applyOptions(dialog, options); createKMessageBox(dialog, buttonBox, QMessageBox::Critical, text, strlist, QString(), nullptr, options); } void errorList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &caption, Options options) { errorListInternal(new QDialog(parent), text, strlist, caption, options); } static void detailedErrorInternal(QDialog *dialog, const QString &text, const QString &details, const QString &caption, Options options) { dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Error") : caption); dialog->setObjectName(QStringLiteral("error")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->addButton(QDialogButtonBox::Ok); buttonBox->button(QDialogButtonBox::Ok)->setFocus(); applyOptions(dialog, options); createKMessageBox(dialog, buttonBox, QMessageBox::Critical, text, QStringList(), QString(), nullptr, options, details); } void detailedError(QWidget *parent, const QString &text, const QString &details, const QString &caption, Options options) { detailedErrorInternal(new QDialog(parent), text, details, caption, options); } static void sorryInternal(QDialog *dialog, const QString &text, const QString &caption, Options options) { dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Sorry") : caption); dialog->setObjectName(QStringLiteral("sorry")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok); applyOptions(dialog, options); createKMessageBox(dialog, buttonBox, QMessageBox::Warning, text, QStringList(), QString(), nullptr, options); } void sorry(QWidget *parent, const QString &text, const QString &caption, Options options) { sorryInternal(new QDialog(parent), text, caption, options); } static void detailedSorryInternal(QDialog *dialog, const QString &text, const QString &details, const QString &caption, Options options) { dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Sorry") : caption); dialog->setObjectName(QStringLiteral("sorry")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->addButton(QDialogButtonBox::Ok); buttonBox->button(QDialogButtonBox::Ok)->setFocus(); applyOptions(dialog, options); createKMessageBox(dialog, buttonBox, QMessageBox::Warning, text, QStringList(), QString(), nullptr, options, details); } void detailedSorry(QWidget *parent, const QString &text, const QString &details, const QString &caption, Options options) { detailedSorryInternal(new QDialog(parent), text, details, caption, options); } void information(QWidget *parent, const QString &text, const QString &caption, const QString &dontShowAgainName, Options options) { informationList(parent, text, QStringList(), caption, dontShowAgainName, options); } static void informationListInternal(QDialog *dialog, const QString &text, const QStringList &strlist, const QString &caption, const QString &dontShowAgainName, Options options) { if (!shouldBeShownContinue(dontShowAgainName)) { delete dialog; return; } dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Information") : caption); dialog->setObjectName(QStringLiteral("information")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok); applyOptions(dialog, options); bool checkboxResult = false; createKMessageBox(dialog, buttonBox, QMessageBox::Information, text, strlist, dontShowAgainName.isEmpty() ? QString() : QApplication::translate("KMessageBox", "Do not show this message again"), &checkboxResult, options); if (checkboxResult) { saveDontShowAgainContinue(dontShowAgainName); } } void informationList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &caption, const QString &dontShowAgainName, Options options) { informationListInternal(new QDialog(parent), text, strlist, caption, dontShowAgainName, options); } void about(QWidget *parent, const QString &text, const QString &caption, Options options) { QDialog *dialog = new QDialog(parent, Qt::Dialog); if (!caption.isEmpty()) { dialog->setWindowTitle(caption); } dialog->setObjectName(QStringLiteral("about")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok); applyOptions(dialog, options); if (qApp->windowIcon().isNull()) { QPixmap ret = QMessageBox::standardIcon(QMessageBox::Information); dialog->setWindowIcon(ret); } createKMessageBox(dialog, buttonBox, qApp->windowIcon(), text, QStringList(), QString(), nullptr, options); } static ButtonCode messageBoxInternal(QDialog *dialog, DialogType type, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontShow, Options options) { switch (type) { case QuestionYesNo: return questionYesNoListInternal(dialog, text, QStringList(), caption, buttonYes, buttonNo, dontShow, options); case QuestionYesNoCancel: return questionYesNoCancelInternal(dialog, text, caption, buttonYes, buttonNo, buttonCancel, dontShow, options); case WarningYesNo: return warningYesNoListInternal(dialog, text, QStringList(), caption, buttonYes, buttonNo, dontShow, options); case WarningContinueCancel: return warningContinueCancelListInternal(dialog, text, QStringList(), caption, KGuiItem(buttonYes.text()), buttonCancel, dontShow, options); case WarningYesNoCancel: return warningYesNoCancelListInternal(dialog, text, QStringList(), caption, buttonYes, buttonNo, buttonCancel, dontShow, options); case Information: informationListInternal(dialog, text, QStringList(), caption, dontShow, options); return KMessageBox::Ok; case Error: errorListInternal(dialog, text, QStringList(), caption, options); return KMessageBox::Ok; case Sorry: sorryInternal(dialog, text, caption, options); return KMessageBox::Ok; } return KMessageBox::Cancel; } ButtonCode messageBox(QWidget *parent, DialogType type, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontShow, Options options) { return messageBoxInternal(new QDialog(parent), type, text, caption, buttonYes, buttonNo, buttonCancel, dontShow, options); } ButtonCode questionYesNoWId(WId parent_id, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return questionYesNoListWId(parent_id, text, QStringList(), caption, buttonYes, buttonNo, dontAskAgainName, options); } ButtonCode questionYesNoListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return questionYesNoListInternal(createWIdDialog(parent_id), text, strlist, caption, buttonYes, buttonNo, dontAskAgainName, options); } ButtonCode questionYesNoCancelWId(WId parent_id, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return questionYesNoCancelInternal(createWIdDialog(parent_id), text, caption, buttonYes, buttonNo, buttonCancel, dontAskAgainName, options); } ButtonCode warningYesNoWId(WId parent_id, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return warningYesNoListWId(parent_id, text, QStringList(), caption, buttonYes, buttonNo, dontAskAgainName, options); } ButtonCode warningYesNoListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const QString &dontAskAgainName, Options options) { return warningYesNoListInternal(createWIdDialog(parent_id), text, strlist, caption, buttonYes, buttonNo, dontAskAgainName, options); } ButtonCode warningContinueCancelWId(WId parent_id, const QString &text, const QString &caption, const KGuiItem &buttonContinue, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningContinueCancelListWId(parent_id, text, QStringList(), caption, buttonContinue, buttonCancel, dontAskAgainName, options); } ButtonCode warningContinueCancelListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonContinue, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningContinueCancelListInternal(createWIdDialog(parent_id), text, strlist, caption, buttonContinue, buttonCancel, dontAskAgainName, options); } ButtonCode warningYesNoCancelWId(WId parent_id, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningYesNoCancelListWId(parent_id, text, QStringList(), caption, buttonYes, buttonNo, buttonCancel, dontAskAgainName, options); } ButtonCode warningYesNoCancelListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontAskAgainName, Options options) { return warningYesNoCancelList(createWIdDialog(parent_id), text, strlist, caption, buttonYes, buttonNo, buttonCancel, dontAskAgainName, options); } void errorWId(WId parent_id, const QString &text, const QString &caption, Options options) { errorListWId(parent_id, text, QStringList(), caption, options); } void errorListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &caption, Options options) { errorListInternal(createWIdDialog(parent_id), text, strlist, caption, options); } void detailedErrorWId(WId parent_id, const QString &text, const QString &details, const QString &caption, Options options) { detailedErrorInternal(createWIdDialog(parent_id), text, details, caption, options); } void sorryWId(WId parent_id, const QString &text, const QString &caption, Options options) { QWidget *parent = QWidget::find(parent_id); QDialog *dialog = new QDialog(parent, Qt::Dialog); dialog->setWindowTitle(caption.isEmpty() ? QApplication::translate("KMessageBox", "Sorry") : caption); dialog->setObjectName(QStringLiteral("sorry")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok); applyOptions(dialog, options); if (parent == nullptr && parent_id) { setMainWindow(dialog, parent_id); } createKMessageBox(dialog, buttonBox, QMessageBox::Warning, text, QStringList(), QString(), nullptr, options); } void detailedSorryWId(WId parent_id, const QString &text, const QString &details, const QString &caption, Options options) { detailedSorryInternal(createWIdDialog(parent_id), text, details, caption, options); } void informationWId(WId parent_id, const QString &text, const QString &caption, const QString &dontShowAgainName, Options options) { informationListWId(parent_id, text, QStringList(), caption, dontShowAgainName, options); } void informationListWId(WId parent_id, const QString &text, const QStringList &strlist, const QString &caption, const QString &dontShowAgainName, Options options) { informationListInternal(createWIdDialog(parent_id), text, strlist, caption, dontShowAgainName, options); } ButtonCode messageBoxWId(WId parent_id, DialogType type, const QString &text, const QString &caption, const KGuiItem &buttonYes, const KGuiItem &buttonNo, const KGuiItem &buttonCancel, const QString &dontShow, Options options) { return messageBoxInternal(createWIdDialog(parent_id), type, text, caption, buttonYes, buttonNo, buttonCancel, dontShow, options); } } // namespace #include "kmessagebox.moc" diff --git a/src/kmessagebox_p.cpp b/src/kmessagebox_p.cpp index 8f2af00..a797b71 100644 --- a/src/kmessagebox_p.cpp +++ b/src/kmessagebox_p.cpp @@ -1,156 +1,154 @@ /* This file is part of the KDE libraries * Copyright 2012 David Faure * Copyright 2013 Aurélien Gâteau * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kmessagebox_p.h" #include "loggingcategory.h" #include -#include #include #include #include -#include namespace KMessageBox { class KMessageBoxDontAskAgainQSettingsStorage : public KMessageBoxDontAskAgainInterface { public: KMessageBoxDontAskAgainQSettingsStorage() { m_filePath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1Char('/') + QCoreApplication::instance()->applicationName() + QStringLiteral(".kmessagebox"); QSettings s(m_filePath, QSettings::IniFormat); foreach (const QString &key, s.allKeys()) { m_saved.insert(key, static_cast(s.value(key).toInt())); } } virtual ~KMessageBoxDontAskAgainQSettingsStorage() { QSettings s(m_filePath, QSettings::IniFormat); for (auto it = m_saved.constBegin(); it != m_saved.constEnd(); ++it) { s.setValue(it.key(), static_cast(it.value())); } } bool shouldBeShownYesNo(const QString &dontShowAgainName, KMessageBox::ButtonCode &result) override { KMessageBox::ButtonCode code = m_saved.value(dontShowAgainName, KMessageBox::ButtonCode(0)); if (code == KMessageBox::Yes || code == KMessageBox::No) { result = code; return false; } return true; } bool shouldBeShownContinue(const QString &dontShowAgainName) override { KMessageBox::ButtonCode code = m_saved.value(dontShowAgainName, KMessageBox::Yes); return code == KMessageBox::Yes; } void saveDontShowAgainYesNo(const QString &dontShowAgainName, KMessageBox::ButtonCode result) override { m_saved[dontShowAgainName] = result; } void saveDontShowAgainContinue(const QString &dontShowAgainName) override { m_saved[dontShowAgainName] = KMessageBox::No; } void enableAllMessages() override { m_saved.clear(); } void enableMessage(const QString &dontShowAgainName) override { m_saved.remove(dontShowAgainName); } void setConfig(KConfig *) override { qCWarning(KWidgetsAddonsLog) << "Using QSettings based KMessageBoxDontAskAgainInterface. KMessageBox::setDontShowAgainConfig ignored"; } private: QString m_filePath; QHash m_saved; }; class KMessageBoxNotifyDummy : public KMessageBoxNotifyInterface { public: void sendNotification(QMessageBox::Icon /*notificationType*/, const QString &/*message*/, QWidget * /*parent*/) override {} }; Q_GLOBAL_STATIC(KMessageBoxDontAskAgainQSettingsStorage, s_defaultDontAskAgainInterface) Q_GLOBAL_STATIC(KMessageBoxNotifyDummy, s_defaultNotifyInterface) static KMessageBoxDontAskAgainInterface *s_dontAskAgainInterface = nullptr; static KMessageBoxNotifyInterface *s_notifyInterface = nullptr; static void loadKMessageBoxPlugin() { static bool triedLoadingPlugin = false; if (!triedLoadingPlugin) { triedLoadingPlugin = true; QPluginLoader lib(QStringLiteral("kf5/FrameworkIntegrationPlugin")); QObject *rootObj = lib.instance(); if (rootObj) { s_dontAskAgainInterface = rootObj->property(KMESSAGEBOXDONTASKAGAIN_PROPERTY).value(); s_notifyInterface = rootObj->property(KMESSAGEBOXNOTIFY_PROPERTY).value(); } } if (!s_dontAskAgainInterface) { s_dontAskAgainInterface = s_defaultDontAskAgainInterface; } if (!s_notifyInterface) { s_notifyInterface = s_defaultNotifyInterface; } } KMessageBoxDontAskAgainInterface *dontAskAgainInterface() { if (!s_dontAskAgainInterface) { loadKMessageBoxPlugin(); } return s_dontAskAgainInterface; } KMessageBoxNotifyInterface *notifyInterface() { if (!s_notifyInterface) { loadKMessageBoxPlugin(); } return s_notifyInterface; } void setDontShowAgainInterface(KMessageBoxDontAskAgainInterface *dontAskAgainInterface) { Q_ASSERT(dontAskAgainInterface != nullptr); s_dontAskAgainInterface = dontAskAgainInterface; } void setNotifyInterface(KMessageBoxNotifyInterface *notifyInterface) { Q_ASSERT(notifyInterface != nullptr); s_notifyInterface = notifyInterface; } } // KMessageBox namespace diff --git a/src/kmessagewidget.cpp b/src/kmessagewidget.cpp index 9e9a7eb..11eb3c0 100644 --- a/src/kmessagewidget.cpp +++ b/src/kmessagewidget.cpp @@ -1,512 +1,511 @@ /* This file is part of the KDE libraries * * Copyright (c) 2011 Aurélien Gâteau * Copyright (c) 2014 Dominik Haumann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include "kmessagewidget.h" #include -#include #include #include #include #include #include #include #include #include #include - +#include //--------------------------------------------------------------------- // KMessageWidgetPrivate //--------------------------------------------------------------------- class KMessageWidgetPrivate { public: void init(KMessageWidget *); KMessageWidget *q; QFrame *content = nullptr; QLabel *iconLabel = nullptr; QLabel *textLabel = nullptr; QToolButton *closeButton = nullptr; QTimeLine *timeLine = nullptr; QIcon icon; bool ignoreShowEventDoingAnimatedShow = false; KMessageWidget::MessageType messageType; bool wordWrap; QList buttons; QPixmap contentSnapShot; void createLayout(); void applyStyleSheet(); void updateSnapShot(); void updateLayout(); void slotTimeLineChanged(qreal); void slotTimeLineFinished(); int bestContentHeight() const; }; void KMessageWidgetPrivate::init(KMessageWidget *q_ptr) { q = q_ptr; q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); // Note: when changing the value 500, also update KMessageWidgetTest timeLine = new QTimeLine(500, q); QObject::connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(slotTimeLineChanged(qreal))); QObject::connect(timeLine, SIGNAL(finished()), q, SLOT(slotTimeLineFinished())); content = new QFrame(q); content->setObjectName(QStringLiteral("contentWidget")); content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); wordWrap = false; iconLabel = new QLabel(content); iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); iconLabel->hide(); textLabel = new QLabel(content); textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); QObject::connect(textLabel, &QLabel::linkActivated, q, &KMessageWidget::linkActivated); QObject::connect(textLabel, &QLabel::linkHovered, q, &KMessageWidget::linkHovered); QAction *closeAction = new QAction(q); closeAction->setText(KMessageWidget::tr("&Close")); closeAction->setToolTip(KMessageWidget::tr("Close message")); closeAction->setIcon(q->style()->standardIcon(QStyle::SP_DialogCloseButton)); QObject::connect(closeAction, &QAction::triggered, q, &KMessageWidget::animatedHide); closeButton = new QToolButton(content); closeButton->setAutoRaise(true); closeButton->setDefaultAction(closeAction); q->setMessageType(KMessageWidget::Information); } void KMessageWidgetPrivate::createLayout() { delete content->layout(); content->resize(q->size()); qDeleteAll(buttons); buttons.clear(); Q_FOREACH (QAction *action, q->actions()) { QToolButton *button = new QToolButton(content); button->setDefaultAction(action); button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); buttons.append(button); } // AutoRaise reduces visual clutter, but we don't want to turn it on if // there are other buttons, otherwise the close button will look different // from the others. closeButton->setAutoRaise(buttons.isEmpty()); if (wordWrap) { QGridLayout *layout = new QGridLayout(content); // Set alignment to make sure icon does not move down if text wraps layout->addWidget(iconLabel, 0, 0, 1, 1, Qt::AlignHCenter | Qt::AlignTop); layout->addWidget(textLabel, 0, 1); if (buttons.isEmpty()) { // Use top-vertical alignment like the icon does. layout->addWidget(closeButton, 0, 2, 1, 1, Qt::AlignHCenter | Qt::AlignTop); } else { // Use an additional layout in row 1 for the buttons. QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); Q_FOREACH (QToolButton *button, buttons) { // For some reason, calling show() is necessary if wordwrap is true, // otherwise the buttons do not show up. It is not needed if // wordwrap is false. button->show(); buttonLayout->addWidget(button); } buttonLayout->addWidget(closeButton); layout->addItem(buttonLayout, 1, 0, 1, 2); } } else { QHBoxLayout *layout = new QHBoxLayout(content); layout->addWidget(iconLabel); layout->addWidget(textLabel); for (QToolButton *button : qAsConst(buttons)) { layout->addWidget(button); } layout->addWidget(closeButton); }; if (q->isVisible()) { q->setFixedHeight(content->sizeHint().height()); } q->updateGeometry(); } void KMessageWidgetPrivate::applyStyleSheet() { QColor bgBaseColor; // We have to hardcode colors here because KWidgetsAddons is a tier 1 framework // and therefore can't depend on any other KDE Frameworks // The following RGB color values come from the "default" scheme in kcolorscheme.cpp switch (messageType) { case KMessageWidget::Positive: bgBaseColor.setRgb(39, 174, 96); // Window: ForegroundPositive break; case KMessageWidget::Information: bgBaseColor.setRgb(61, 174, 233); // Window: ForegroundActive break; case KMessageWidget::Warning: bgBaseColor.setRgb(246, 116, 0); // Window: ForegroundNeutral break; case KMessageWidget::Error: bgBaseColor.setRgb(218, 68, 83); // Window: ForegroundNegative break; } const qreal bgBaseColorAlpha = 0.2; bgBaseColor.setAlphaF(bgBaseColorAlpha); const QPalette palette = QGuiApplication::palette(); const QColor windowColor = palette.window().color(); const QColor textColor = palette.text().color(); const QColor border = bgBaseColor; // Generate a final background color from overlaying bgBaseColor over windowColor const int newRed = (bgBaseColor.red() * bgBaseColorAlpha) + (windowColor.red() * (1 - bgBaseColorAlpha)); const int newGreen = (bgBaseColor.green() * bgBaseColorAlpha) + (windowColor.green() * (1 - bgBaseColorAlpha)); const int newBlue = (bgBaseColor.blue() * bgBaseColorAlpha) + (windowColor.blue() * (1 - bgBaseColorAlpha)); const QColor bgFinalColor = QColor(newRed, newGreen, newBlue); content->setStyleSheet( QString::fromLatin1(".QFrame {" "background-color: %1;" "border-radius: 4px;" "border: 2px solid %2;" "margin: %3px;" "}" ".QLabel { color: %4; }" ) .arg(bgFinalColor.name()) .arg(border.name()) // DefaultFrameWidth returns the size of the external margin + border width. We know our border is 1px, so we subtract this from the frame normal QStyle FrameWidth to get our margin .arg(q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, q) - 1) .arg(textColor.name()) ); } void KMessageWidgetPrivate::updateLayout() { if (content->layout()) { createLayout(); } } void KMessageWidgetPrivate::updateSnapShot() { // Attention: updateSnapShot calls QWidget::render(), which causes the whole // window layouts to be activated. Calling this method from resizeEvent() // can lead to infinite recursion, see: // https://bugs.kde.org/show_bug.cgi?id=311336 contentSnapShot = QPixmap(content->size() * q->devicePixelRatio()); contentSnapShot.setDevicePixelRatio(q->devicePixelRatio()); contentSnapShot.fill(Qt::transparent); content->render(&contentSnapShot, QPoint(), QRegion(), QWidget::DrawChildren); } void KMessageWidgetPrivate::slotTimeLineChanged(qreal value) { q->setFixedHeight(qMin(value * 2, qreal(1.0)) * content->height()); q->update(); } void KMessageWidgetPrivate::slotTimeLineFinished() { if (timeLine->direction() == QTimeLine::Forward) { // Show // We set the whole geometry here, because it may be wrong if a // KMessageWidget is shown right when the toplevel window is created. content->setGeometry(0, 0, q->width(), bestContentHeight()); // notify about finished animation emit q->showAnimationFinished(); } else { // hide and notify about finished animation q->hide(); emit q->hideAnimationFinished(); } } int KMessageWidgetPrivate::bestContentHeight() const { int height = content->heightForWidth(q->width()); if (height == -1) { height = content->sizeHint().height(); } return height; } //--------------------------------------------------------------------- // KMessageWidget //--------------------------------------------------------------------- KMessageWidget::KMessageWidget(QWidget *parent) : QFrame(parent) , d(new KMessageWidgetPrivate) { d->init(this); } KMessageWidget::KMessageWidget(const QString &text, QWidget *parent) : QFrame(parent) , d(new KMessageWidgetPrivate) { d->init(this); setText(text); } KMessageWidget::~KMessageWidget() { delete d; } QString KMessageWidget::text() const { return d->textLabel->text(); } void KMessageWidget::setText(const QString &text) { d->textLabel->setText(text); updateGeometry(); } KMessageWidget::MessageType KMessageWidget::messageType() const { return d->messageType; } void KMessageWidget::setMessageType(KMessageWidget::MessageType type) { d->messageType = type; d->applyStyleSheet(); } QSize KMessageWidget::sizeHint() const { ensurePolished(); return d->content->sizeHint(); } QSize KMessageWidget::minimumSizeHint() const { ensurePolished(); return d->content->minimumSizeHint(); } bool KMessageWidget::event(QEvent *event) { if (event->type() == QEvent::Polish && !d->content->layout()) { d->createLayout(); } else if (event->type() == QEvent::PaletteChange) { d->applyStyleSheet(); } else if (event->type() == QEvent::Show && !d->ignoreShowEventDoingAnimatedShow) { if ((height() != d->content->height()) || (d->content->pos().y() != 0)) { d->content->move(0, 0); setFixedHeight(d->content->height()); } } return QFrame::event(event); } void KMessageWidget::resizeEvent(QResizeEvent *event) { QFrame::resizeEvent(event); if (d->timeLine->state() == QTimeLine::NotRunning) { d->content->resize(width(), d->bestContentHeight()); } } int KMessageWidget::heightForWidth(int width) const { ensurePolished(); return d->content->heightForWidth(width); } void KMessageWidget::paintEvent(QPaintEvent *event) { QFrame::paintEvent(event); if (d->timeLine->state() == QTimeLine::Running) { QPainter painter(this); painter.setOpacity(d->timeLine->currentValue() * d->timeLine->currentValue()); painter.drawPixmap(0, 0, d->contentSnapShot); } } bool KMessageWidget::wordWrap() const { return d->wordWrap; } void KMessageWidget::setWordWrap(bool wordWrap) { d->wordWrap = wordWrap; d->textLabel->setWordWrap(wordWrap); QSizePolicy policy = sizePolicy(); policy.setHeightForWidth(wordWrap); setSizePolicy(policy); d->updateLayout(); // Without this, when user does wordWrap -> !wordWrap -> wordWrap, a minimum // height is set, causing the widget to be too high. // Mostly visible in test programs. if (wordWrap) { setMinimumHeight(0); } } bool KMessageWidget::isCloseButtonVisible() const { return d->closeButton->isVisible(); } void KMessageWidget::setCloseButtonVisible(bool show) { d->closeButton->setVisible(show); updateGeometry(); } void KMessageWidget::addAction(QAction *action) { QFrame::addAction(action); d->updateLayout(); } void KMessageWidget::removeAction(QAction *action) { QFrame::removeAction(action); d->updateLayout(); } void KMessageWidget::animatedShow() { // Test before styleHint, as there might have been a style change while animation was running if (isHideAnimationRunning()) { d->timeLine->stop(); emit hideAnimationFinished(); } if (!style()->styleHint(QStyle::SH_Widget_Animate, nullptr, this) || (parentWidget() && !parentWidget()->isVisible())) { show(); emit showAnimationFinished(); return; } if (isVisible() && (d->timeLine->state() == QTimeLine::NotRunning) && (height() == d->bestContentHeight()) && (d->content->pos().y() == 0)) { emit showAnimationFinished(); return; } d->ignoreShowEventDoingAnimatedShow = true; show(); d->ignoreShowEventDoingAnimatedShow = false; setFixedHeight(0); int wantedHeight = d->bestContentHeight(); d->content->setGeometry(0, -wantedHeight, width(), wantedHeight); d->updateSnapShot(); d->timeLine->setDirection(QTimeLine::Forward); if (d->timeLine->state() == QTimeLine::NotRunning) { d->timeLine->start(); } } void KMessageWidget::animatedHide() { // test this before isVisible, as animatedShow might have been called directly before, // so the first timeline event is not yet done and the widget is still hidden // And before styleHint, as there might have been a style change while animation was running if (isShowAnimationRunning()) { d->timeLine->stop(); emit showAnimationFinished(); } if (!style()->styleHint(QStyle::SH_Widget_Animate, nullptr, this)) { hide(); emit hideAnimationFinished(); return; } if (!isVisible()) { // explicitly hide it, so it stays hidden in case it is only not visible due to the parents hide(); emit hideAnimationFinished(); return; } d->content->move(0, -d->content->height()); d->updateSnapShot(); d->timeLine->setDirection(QTimeLine::Backward); if (d->timeLine->state() == QTimeLine::NotRunning) { d->timeLine->start(); } } bool KMessageWidget::isHideAnimationRunning() const { return (d->timeLine->direction() == QTimeLine::Backward) && (d->timeLine->state() == QTimeLine::Running); } bool KMessageWidget::isShowAnimationRunning() const { return (d->timeLine->direction() == QTimeLine::Forward) && (d->timeLine->state() == QTimeLine::Running); } QIcon KMessageWidget::icon() const { return d->icon; } void KMessageWidget::setIcon(const QIcon &icon) { d->icon = icon; if (d->icon.isNull()) { d->iconLabel->hide(); } else { const int size = style()->pixelMetric(QStyle::PM_ToolBarIconSize); d->iconLabel->setPixmap(d->icon.pixmap(size)); d->iconLabel->show(); } } #include "moc_kmessagewidget.cpp" diff --git a/src/kmimetypeeditor.h b/src/kmimetypeeditor.h index 2c25700..1de7ca5 100644 --- a/src/kmimetypeeditor.h +++ b/src/kmimetypeeditor.h @@ -1,43 +1,42 @@ /* This file is part of the KDE libraries Copyright (C) 2014 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KMIMETYPE_EDITOR_H #define KMIMETYPE_EDITOR_H #include -#include #include /** * This namespace provides a method for starting the file types editor. * @since 5.4 */ namespace KMimeTypeEditor { /** * Starts the file types editor for a given MIME type. * @param mimeType the mimetype to edit, e.g. "text/plain" * @param widget the parent widget * @since 5.4 */ KWIDGETSADDONS_EXPORT void editMimeType(const QString &mimeType, QWidget *widget); } #endif diff --git a/src/kmultitabbar.cpp b/src/kmultitabbar.cpp index a807621..b303b5a 100644 --- a/src/kmultitabbar.cpp +++ b/src/kmultitabbar.cpp @@ -1,690 +1,688 @@ /*************************************************************************** kmultitabbar.cpp - description ------------------- begin : 2001 copyright : (C) 2001,2002,2003 by Joseph Wenninger ***************************************************************************/ /*************************************************************************** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #include "kmultitabbar.h" #include "kmultitabbar_p.h" #include "moc_kmultitabbar.cpp" #include "moc_kmultitabbar_p.cpp" -#include -#include #include -#include #include #include +#include #include /** A bit of an overview about what's going on here: There are two sorts of things that can be in the tab bar: tabs and regular buttons. The former are managed by KMultiTabBarInternal, the later by the KMultiTabBar itself. */ class KMultiTabBarPrivate { public: class KMultiTabBarInternal *m_internal; QBoxLayout *m_l; QFrame *m_btnTabSep; QList m_buttons; KMultiTabBar::KMultiTabBarPosition m_position; }; KMultiTabBarInternal::KMultiTabBarInternal(QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos): QFrame(parent) { m_position = pos; if (pos == KMultiTabBar::Left || pos == KMultiTabBar::Right) { mainLayout = new QVBoxLayout(this); } else { mainLayout = new QHBoxLayout(this); } mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); mainLayout->addStretch(); setFrameStyle(NoFrame); setBackgroundRole(QPalette::Window); } KMultiTabBarInternal::~KMultiTabBarInternal() { qDeleteAll(m_tabs); m_tabs.clear(); } void KMultiTabBarInternal::setStyle(enum KMultiTabBar::KMultiTabBarStyle style) { m_style = style; for (int i = 0; i < m_tabs.count(); i++) { m_tabs.at(i)->setStyle(m_style); } updateGeometry(); } void KMultiTabBarInternal::contentsMousePressEvent(QMouseEvent *ev) { ev->ignore(); } void KMultiTabBarInternal::mousePressEvent(QMouseEvent *ev) { ev->ignore(); } KMultiTabBarTab *KMultiTabBarInternal::tab(int id) const { QListIterator it(m_tabs); while (it.hasNext()) { KMultiTabBarTab *tab = it.next(); if (tab->id() == id) { return tab; } } return nullptr; } int KMultiTabBarInternal::appendTab(const QIcon &icon, int id, const QString &text) { KMultiTabBarTab *tab; m_tabs.append(tab = new KMultiTabBarTab(icon, text, id, this, m_position, m_style)); // Insert before the stretch.. mainLayout->insertWidget(m_tabs.size() - 1, tab); tab->show(); return 0; } int KMultiTabBarInternal::appendTab(const QPixmap &pic, int id, const QString &text) { // reuse icon variant return appendTab(QIcon(pic), id, text); } void KMultiTabBarInternal::removeTab(int id) { for (int pos = 0; pos < m_tabs.count(); pos++) { if (m_tabs.at(pos)->id() == id) { // remove & delete the tab delete m_tabs.takeAt(pos); break; } } } void KMultiTabBarInternal::setPosition(enum KMultiTabBar::KMultiTabBarPosition pos) { m_position = pos; for (int i = 0; i < m_tabs.count(); i++) { m_tabs.at(i)->setPosition(m_position); } updateGeometry(); } // KMultiTabBarButton /////////////////////////////////////////////////////////////////////////////// KMultiTabBarButton::KMultiTabBarButton(const QIcon &icon, const QString &text, int id, QWidget *parent) : QPushButton(icon, text, parent), m_id(id), d(nullptr) { connect(this, &QPushButton::clicked, this, &KMultiTabBarButton::slotClicked); // we can't see the focus, so don't take focus. #45557 // If keyboard navigation is wanted, then only the bar should take focus, // and arrows could change the focused button; but generally, tabbars don't take focus anyway. setFocusPolicy(Qt::NoFocus); setAttribute(Qt::WA_LayoutUsesWidgetRect); Q_UNUSED(d); } KMultiTabBarButton::KMultiTabBarButton(const QPixmap &pic, const QString &text, int id, QWidget *parent) : QPushButton(QIcon(pic), text, parent), m_id(id), d(nullptr) { connect(this, &QPushButton::clicked, this, &KMultiTabBarButton::slotClicked); // we can't see the focus, so don't take focus. #45557 // If keyboard navigation is wanted, then only the bar should take focus, // and arrows could change the focused button; but generally, tabbars don't take focus anyway. setFocusPolicy(Qt::NoFocus); setAttribute(Qt::WA_LayoutUsesWidgetRect); Q_UNUSED(d); } KMultiTabBarButton::~KMultiTabBarButton() { } void KMultiTabBarButton::setText(const QString &text) { QPushButton::setText(text); } void KMultiTabBarButton::slotClicked() { updateGeometry(); emit clicked(m_id); } int KMultiTabBarButton::id() const { return m_id; } void KMultiTabBarButton::hideEvent(QHideEvent *he) { QPushButton::hideEvent(he); KMultiTabBar *tb = dynamic_cast(parentWidget()); if (tb) { tb->updateSeparator(); } } void KMultiTabBarButton::showEvent(QShowEvent *he) { QPushButton::showEvent(he); KMultiTabBar *tb = dynamic_cast(parentWidget()); if (tb) { tb->updateSeparator(); } } void KMultiTabBarButton::paintEvent(QPaintEvent *) { QStyleOptionButton opt; opt.initFrom(this); opt.icon = icon(); opt.iconSize = iconSize(); // removes the QStyleOptionButton::HasMenu ButtonFeature opt.features = QStyleOptionButton::Flat; QPainter painter(this); style()->drawControl(QStyle::CE_PushButton, &opt, &painter, this); } // KMultiTabBarTab /////////////////////////////////////////////////////////////////////////////// KMultiTabBarTab::KMultiTabBarTab(const QIcon &icon, const QString &text, int id, QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos, KMultiTabBar::KMultiTabBarStyle style) : KMultiTabBarButton(icon, text, id, parent), m_style(style), d(nullptr) { m_position = pos; setToolTip(text); setCheckable(true); // shrink down to icon only, but prefer to show text if it's there setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); } KMultiTabBarTab::KMultiTabBarTab(const QPixmap &pic, const QString &text, int id, QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos, KMultiTabBar::KMultiTabBarStyle style) : KMultiTabBarButton(pic, text, id, parent), m_style(style), d(nullptr) { m_position = pos; setToolTip(text); setCheckable(true); // shrink down to icon only, but prefer to show text if it's there setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); } KMultiTabBarTab::~KMultiTabBarTab() { } void KMultiTabBarTab::setPosition(KMultiTabBar::KMultiTabBarPosition pos) { m_position = pos; updateGeometry(); } void KMultiTabBarTab::setStyle(KMultiTabBar::KMultiTabBarStyle style) { m_style = style; updateGeometry(); } QPixmap KMultiTabBarTab::iconPixmap() const { int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this); return icon().pixmap(iconSize); } void KMultiTabBarTab::initStyleOption(QStyleOptionToolButton *opt) const { opt->initFrom(this); // Setup icon.. if (!icon().isNull()) { opt->iconSize = iconPixmap().size(); opt->icon = icon(); } // Should we draw text? if (shouldDrawText()) { opt->text = text(); } opt->state |= QStyle::State_AutoRaise; if (underMouse()) { opt->state |= QStyle::State_MouseOver | QStyle::State_Raised; } if (isChecked()) { opt->state |= QStyle::State_Sunken | QStyle::State_On; } opt->font = font(); opt->toolButtonStyle = shouldDrawText() ? Qt::ToolButtonTextBesideIcon : Qt::ToolButtonIconOnly; opt->subControls = QStyle::SC_ToolButton; } QSize KMultiTabBarTab::sizeHint() const { return computeSizeHint(shouldDrawText()); } QSize KMultiTabBarTab::minimumSizeHint() const { return computeSizeHint(false); } void KMultiTabBarTab::computeMargins(int *hMargin, int *vMargin) const { // Unfortunately, QStyle does not give us enough information to figure out // where to place things, so we try to reverse-engineer it QStyleOptionToolButton opt; initStyleOption(&opt); QPixmap iconPix = iconPixmap(); QSize trialSize = iconPix.size() / iconPix.devicePixelRatio(); QSize expandSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, trialSize, this); *hMargin = (expandSize.width() - trialSize.width()) / 2; *vMargin = (expandSize.height() - trialSize.height()) / 2; } QSize KMultiTabBarTab::computeSizeHint(bool withText) const { // Compute as horizontal first, then flip around if need be. QStyleOptionToolButton opt; initStyleOption(&opt); int hMargin, vMargin; computeMargins(&hMargin, &vMargin); // Compute interior size, starting from pixmap.. QPixmap iconPix = iconPixmap(); QSize size = iconPix.size() / iconPix.devicePixelRatio(); // Always include text height in computation, to avoid resizing the minor direction // when expanding text.. QSize textSize = fontMetrics().size(0, text()); size.setHeight(qMax(size.height(), textSize.height())); // Pick margins for major/minor direction, depending on orientation int majorMargin = isVertical() ? vMargin : hMargin; int minorMargin = isVertical() ? hMargin : vMargin; size.setWidth(size.width() + 2 * majorMargin); size.setHeight(size.height() + 2 * minorMargin); if (withText) // Add enough room for the text, and an extra major margin. { size.setWidth(size.width() + textSize.width() + majorMargin); } // flip time? if (isVertical()) { return QSize(size.height(), size.width()); } else { return size; } } void KMultiTabBarTab::setState(bool newState) { setChecked(newState); updateGeometry(); } void KMultiTabBarTab::setIcon(const QString &icon) { const QIcon i = QIcon::fromTheme(icon); const int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this); setIcon(i.pixmap(iconSize)); } void KMultiTabBarTab::setIcon(const QPixmap &icon) { QPushButton::setIcon(icon); } bool KMultiTabBarTab::shouldDrawText() const { return (m_style == KMultiTabBar::KDEV3ICON) || isChecked(); } bool KMultiTabBarTab::isVertical() const { return m_position == KMultiTabBar::Right || m_position == KMultiTabBar::Left; } void KMultiTabBarTab::paintEvent(QPaintEvent *) { QPainter painter(this); QStyleOptionToolButton opt; initStyleOption(&opt); // Paint bevel.. if (underMouse() || isChecked()) { opt.text.clear(); opt.icon = QIcon(); style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &painter, this); } int hMargin, vMargin; computeMargins(&hMargin, &vMargin); // We first figure out how much room we have for the text, based on // icon size and margin, try to fit in by eliding, and perhaps // give up on drawing the text entirely if we're too short on room QPixmap icon = iconPixmap(); int textRoom = 0; int iconRoom = 0; QString t; if (shouldDrawText()) { if (isVertical()) { iconRoom = icon.height() / icon.devicePixelRatio() + 2 * vMargin; textRoom = height() - iconRoom - vMargin; } else { iconRoom = icon.width() / icon.devicePixelRatio() + 2 * hMargin; textRoom = width() - iconRoom - hMargin; } t = painter.fontMetrics().elidedText(text(), Qt::ElideRight, textRoom); // See whether anything is left. Qt will return either // ... or the ellipsis unicode character, 0x2026 if (t == QLatin1String("...") || t == QChar(0x2026)) { t.clear(); } } // Label time.... Simple case: no text, so just plop down the icon right in the center // We only do this when the button never draws the text, to avoid jumps in icon position // when resizing if (!shouldDrawText()) { style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter | Qt::AlignVCenter, icon); return; } // Now where the icon/text goes depends on text direction and tab position QRect iconArea; QRect labelArea; bool bottomIcon = false; bool rtl = layoutDirection() == Qt::RightToLeft; if (isVertical()) { if (m_position == KMultiTabBar::Left && !rtl) { bottomIcon = true; } if (m_position == KMultiTabBar::Right && rtl) { bottomIcon = true; } } //alignFlags = Qt::AlignLeading | Qt::AlignVCenter; if (isVertical()) { if (bottomIcon) { labelArea = QRect(0, vMargin, width(), textRoom); iconArea = QRect(0, vMargin + textRoom, width(), iconRoom); } else { labelArea = QRect(0, iconRoom, width(), textRoom); iconArea = QRect(0, 0, width(), iconRoom); } } else { // Pretty simple --- depends only on RTL/LTR if (rtl) { labelArea = QRect(hMargin, 0, textRoom, height()); iconArea = QRect(hMargin + textRoom, 0, iconRoom, height()); } else { labelArea = QRect(iconRoom, 0, textRoom, height()); iconArea = QRect(0, 0, iconRoom, height()); } } style()->drawItemPixmap(&painter, iconArea, Qt::AlignCenter | Qt::AlignVCenter, icon); if (t.isEmpty()) { return; } QRect labelPaintArea = labelArea; if (isVertical()) { // If we're vertical, we paint to a simple 0,0 origin rect, // and get the transformations to get us in the right place labelPaintArea = QRect(0, 0, labelArea.height(), labelArea.width()); QTransform tr; if (bottomIcon) { tr.translate(labelArea.x(), labelPaintArea.width() + labelArea.y()); tr.rotate(-90); } else { tr.translate(labelPaintArea.height() + labelArea.x(), labelArea.y()); tr.rotate(90); } painter.setTransform(tr); } opt.text = t; opt.icon = QIcon(); opt.rect = labelPaintArea; style()->drawControl(QStyle::CE_ToolButtonLabel, &opt, &painter, this); } // KMultiTabBar /////////////////////////////////////////////////////////////////////////////// KMultiTabBar::KMultiTabBar(QWidget *parent) : KMultiTabBar(Left, parent) { } KMultiTabBar::KMultiTabBar(KMultiTabBarPosition pos, QWidget *parent) : QWidget(parent), d(new KMultiTabBarPrivate) { if (pos == Left || pos == Right) { d->m_l = new QVBoxLayout(this); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding/*, true*/); } else { d->m_l = new QHBoxLayout(this); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed/*, true*/); } d->m_l->setContentsMargins(0, 0, 0, 0); d->m_l->setSpacing(0); d->m_internal = new KMultiTabBarInternal(this, pos); setPosition(pos); setStyle(VSNET); d->m_l->insertWidget(0, d->m_internal); d->m_l->insertWidget(0, d->m_btnTabSep = new QFrame(this)); d->m_btnTabSep->setFixedHeight(4); d->m_btnTabSep->setFrameStyle(QFrame::Panel | QFrame::Sunken); d->m_btnTabSep->setLineWidth(2); d->m_btnTabSep->hide(); updateGeometry(); } KMultiTabBar::~KMultiTabBar() { qDeleteAll(d->m_buttons); d->m_buttons.clear(); delete d; } int KMultiTabBar::appendButton(const QIcon &icon, int id, QMenu *popup, const QString &) { KMultiTabBarButton *btn = new KMultiTabBarButton(icon, QString(), id, this); // a button with a QMenu can have another size. Make sure the button has always the same size. btn->setFixedWidth(btn->height()); btn->setMenu(popup); d->m_buttons.append(btn); d->m_l->insertWidget(0, btn); btn->show(); d->m_btnTabSep->show(); return 0; } #ifndef KWIDGETSADDONS_NO_DEPRECATED int KMultiTabBar::appendButton(const QPixmap &pic, int id, QMenu *popup, const QString &x) { // reuse icon variant return appendButton(QIcon(pic), id, popup, x); } #endif void KMultiTabBar::updateSeparator() { bool hideSep = true; QListIterator it(d->m_buttons); while (it.hasNext()) { if (it.next()->isVisibleTo(this)) { hideSep = false; break; } } if (hideSep) { d->m_btnTabSep->hide(); } else { d->m_btnTabSep->show(); } } int KMultiTabBar::appendTab(const QIcon &icon, int id, const QString &text) { d->m_internal->appendTab(icon, id, text); return 0; } #ifndef KWIDGETSADDONS_NO_DEPRECATED int KMultiTabBar::appendTab(const QPixmap &pic, int id, const QString &text) { d->m_internal->appendTab(pic, id, text); return 0; } #endif KMultiTabBarButton *KMultiTabBar::button(int id) const { QListIterator it(d->m_buttons); while (it.hasNext()) { KMultiTabBarButton *button = it.next(); if (button->id() == id) { return button; } } return nullptr; } KMultiTabBarTab *KMultiTabBar::tab(int id) const { return d->m_internal->tab(id); } void KMultiTabBar::removeButton(int id) { for (int pos = 0; pos < d->m_buttons.count(); pos++) { if (d->m_buttons.at(pos)->id() == id) { d->m_buttons.takeAt(pos)->deleteLater(); break; } } if (d->m_buttons.isEmpty()) { d->m_btnTabSep->hide(); } } void KMultiTabBar::removeTab(int id) { d->m_internal->removeTab(id); } void KMultiTabBar::setTab(int id, bool state) { KMultiTabBarTab *ttab = tab(id); if (ttab) { ttab->setState(state); } } bool KMultiTabBar::isTabRaised(int id) const { KMultiTabBarTab *ttab = tab(id); if (ttab) { return ttab->isChecked(); } return false; } void KMultiTabBar::setStyle(KMultiTabBarStyle style) { d->m_internal->setStyle(style); } KMultiTabBar::KMultiTabBarStyle KMultiTabBar::tabStyle() const { return d->m_internal->m_style; } void KMultiTabBar::setPosition(KMultiTabBarPosition pos) { d->m_position = pos; d->m_internal->setPosition(pos); } KMultiTabBar::KMultiTabBarPosition KMultiTabBar::position() const { return d->m_position; } void KMultiTabBar::fontChange(const QFont & /* oldFont */) { updateGeometry(); } diff --git a/src/kmultitabbar.h b/src/kmultitabbar.h index 4cf6b0f..9566e19 100644 --- a/src/kmultitabbar.h +++ b/src/kmultitabbar.h @@ -1,303 +1,301 @@ /*************************************************************************** kmultitabbar.h - description ------------------- begin : 2001 copyright : (C) 2001,2002,2003 by Joseph Wenninger ***************************************************************************/ /*************************************************************************** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #ifndef _KMultitabbar_h_ #define _KMultitabbar_h_ -#include #include -#include #include #include class QPixmap; class QPainter; class QMenu; class QStyleOptionToolButton; class KMultiTabBarPrivate; class KMultiTabBarTabPrivate; class KMultiTabBarButtonPrivate; class KMultiTabBarInternal; /** * @class KMultiTabBar kmultitabbar.h KMultiTabBar * * A Widget for horizontal and vertical tabs. * (Note that in Qt4, QTabBar can be vertical as well) * * It is possible to add normal buttons to the top/left * The handling if only one tab at a time or multiple tabs * should be raisable is left to the "user". * * \image html kmultitabbar.png "KMultiTabBar Widget" * * @author Joseph Wenninger */ class KWIDGETSADDONS_EXPORT KMultiTabBar: public QWidget { Q_OBJECT Q_PROPERTY(KMultiTabBarPosition position READ position WRITE setPosition) Q_PROPERTY(KMultiTabBarStyle tabStyle READ tabStyle WRITE setStyle) public: enum KMultiTabBarPosition { Left, Right, Top, Bottom }; Q_ENUM(KMultiTabBarPosition) /** * The list of available styles for KMultiTabBar */ enum KMultiTabBarStyle { VSNET = 0, ///< Visual Studio .Net like, always shows icon, only show the text of active tabs KDEV3ICON = 2, ///< KDevelop 3 like, always shows the text and icons STYLELAST = 0xffff }; Q_ENUM(KMultiTabBarStyle) /** * Create a KMultiTabBar with Left as KMultiTabBar position. * @param parent The parent of the widget. * @since 5.24 */ explicit KMultiTabBar(QWidget *parent = nullptr); explicit KMultiTabBar(KMultiTabBarPosition pos, QWidget *parent = nullptr); virtual ~KMultiTabBar(); /** * append a new button to the button area. The button can later on be accessed with button(ID) * eg for connecting signals to it * @param icon a icon for the button * @param id an arbitrary ID value. It will be emitted in the clicked signal for identifying the button * if more than one button is connected to a signals. * @param popup A popup menu which should be displayed if the button is clicked * @param not_used_yet will be used for a popup text in the future * @since 5.13 */ int appendButton(const QIcon &icon, int id = -1, QMenu *popup = nullptr, const QString ¬_used_yet = QString()); #ifndef KWIDGETSADDONS_NO_DEPRECATED /** * append a new button to the button area. The button can later on be accessed with button(ID) * eg for connecting signals to it * * @deprecated since 5.13, use the appendButton() with QIcon * * @param pic a pixmap for the button * @param id an arbitraty ID value. It will be emitted in the clicked signal for identifying the button * if more than one button is connected to a signals. * @param popup A popup menu which should be displayed if the button is clicked * @param not_used_yet will be used for a popup text in the future */ KWIDGETSADDONS_DEPRECATED int appendButton(const QPixmap &pic, int id = -1, QMenu *popup = nullptr, const QString ¬_used_yet = QString()); #endif /** * remove a button with the given ID */ void removeButton(int id); /** * append a new tab to the tab area. It can be accessed lateron with tabb(id); * @param icon a icon for the tab * @param id an arbitrary ID which can be used later on to identify the tab * @param text if a mode with text is used it will be the tab text, otherwise a mouse over hint * @since 5.13 */ int appendTab(const QIcon &icon, int id = -1, const QString &text = QString()); #ifndef KWIDGETSADDONS_NO_DEPRECATED /** * append a new tab to the tab area. It can be accessed lateron with tabb(id); * * @deprecated since 5.13, use the appendTab() with QIcon * * @param pic a bitmap for the tab * @param id an arbitrary ID which can be used later on to identify the tab * @param text if a mode with text is used it will be the tab text, otherwise a mouse over hint */ KWIDGETSADDONS_DEPRECATED int appendTab(const QPixmap &pic, int id = -1, const QString &text = QString()); #endif /** * remove a tab with a given ID */ void removeTab(int id); /** * set a tab to "raised" * @param id The ID of the tab to manipulate * @param state true == activated/raised, false == not active */ void setTab(int id, bool state); /** * return the state of a tab, identified by its ID */ bool isTabRaised(int id) const; /** * get a pointer to a button within the button area identified by its ID */ class KMultiTabBarButton *button(int id) const; /** * get a pointer to a tab within the tab area, identified by its ID */ class KMultiTabBarTab *tab(int id) const; /** * set the real position of the widget. * @param pos if the mode is horizontal, only use top, bottom, if it is vertical use left or right */ void setPosition(KMultiTabBarPosition pos); /** * get the tabbar position. * @return position */ KMultiTabBarPosition position() const; /** * set the display style of the tabs */ void setStyle(KMultiTabBarStyle style); /** * get the display style of the tabs * @return display style */ KMultiTabBarStyle tabStyle() const; protected: friend class KMultiTabBarButton; virtual void fontChange(const QFont &); void updateSeparator(); private: KMultiTabBarPrivate *const d; }; /** * @class KMultiTabBarButton kmultitabbar.h KMultiTabBarButton * * Use KMultiTabBar::appendButton to append a button, which creates a KMultiTabBarButton instance */ class KWIDGETSADDONS_EXPORT KMultiTabBarButton: public QPushButton { Q_OBJECT public: int id() const; ~KMultiTabBarButton() override; public Q_SLOTS: void setText(const QString &text); Q_SIGNALS: /** * this is emitted if the button is clicked * @param id the ID identifying the button */ void clicked(int id); protected Q_SLOTS: virtual void slotClicked(); protected: void hideEvent(class QHideEvent *) override; void showEvent(class QShowEvent *) override; void paintEvent(class QPaintEvent *) override; /** Should not be created directly. Use KMultiTabBar::appendButton */ KMultiTabBarButton(const QIcon &icon, const QString &, int id, QWidget *parent); /** Should not be created directly. Use KMultiTabBar::appendButton */ KMultiTabBarButton(const QPixmap &pic, const QString &, int id, QWidget *parent); private: friend class KMultiTabBar; int m_id; KMultiTabBarButtonPrivate *const d; }; /** * @class KMultiTabBarTab kmultitabbar.h KMultiTabBarTab * * Use KMultiTabBar::appendTab to append a tab, which creates a KMultiTabBarTab instance */ class KWIDGETSADDONS_EXPORT KMultiTabBarTab: public KMultiTabBarButton { Q_OBJECT public: ~KMultiTabBarTab() override; QSize sizeHint() const override; QSize minimumSizeHint() const override; public Q_SLOTS: /** * this is used internally, but can be used by the user, if (s)he wants to * It the according call of KMultiTabBar is invoked though this modifications will be overwritten */ void setPosition(KMultiTabBar::KMultiTabBarPosition); /** * this is used internally, but can be used by the user, if (s)he wants to * It the according call of KMultiTabBar is invoked though this modifications will be overwritten */ void setStyle(KMultiTabBar::KMultiTabBarStyle); /** * set the active state of the tab * @param state true==active false==not active */ void setState(bool state); void setIcon(const QString &); void setIcon(const QPixmap &); protected: void paintEvent(QPaintEvent *) override; private: KMultiTabBar::KMultiTabBarPosition m_position; KMultiTabBar::KMultiTabBarStyle m_style; void computeMargins(int *hMargin, int *vMargin) const; QSize computeSizeHint(bool withText) const; bool shouldDrawText() const; bool isVertical() const; QPixmap iconPixmap() const; void initStyleOption(QStyleOptionToolButton *opt) const; friend class KMultiTabBarInternal; /** * This class should never be created except with the appendTab call of KMultiTabBar */ KMultiTabBarTab(const QIcon &icon, const QString &, int id, QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos, KMultiTabBar::KMultiTabBarStyle style); /** * This class should never be created except with the appendTab call of KMultiTabBar */ KMultiTabBarTab(const QPixmap &pic, const QString &, int id, QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos, KMultiTabBar::KMultiTabBarStyle style); KMultiTabBarTabPrivate *const d; }; #endif diff --git a/src/kmultitabbar_p.h b/src/kmultitabbar_p.h index 70b9de3..9486db3 100644 --- a/src/kmultitabbar_p.h +++ b/src/kmultitabbar_p.h @@ -1,64 +1,65 @@ /*************************************************************************** kmultitabbar_p.h - description ------------------- begin : 2003 copyright : (C) 2003 by Joseph Wenninger ***************************************************************************/ /*************************************************************************** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #ifndef K_MULTI_TAB_BAR_P_H #define K_MULTI_TAB_BAR_P_H #include #include +#include class KMultiTabBarInternal: public QFrame { Q_OBJECT public: KMultiTabBarInternal(QWidget *parent, KMultiTabBar::KMultiTabBarPosition pos); virtual ~KMultiTabBarInternal(); int appendTab(const QIcon &, int = -1, const QString & = QString()); int appendTab(const QPixmap &, int = -1, const QString & = QString()); KMultiTabBarTab *tab(int) const; void removeTab(int); void setPosition(enum KMultiTabBar::KMultiTabBarPosition pos); void setStyle(enum KMultiTabBar::KMultiTabBarStyle style); void showActiveTabTexts(bool show); QList *tabs() { return &m_tabs; } private: friend class KMultiTabBar; QBoxLayout *mainLayout; QList m_tabs; enum KMultiTabBar::KMultiTabBarPosition m_position; enum KMultiTabBar::KMultiTabBarStyle m_style; protected: /** * [contentsM|m]ousePressEvent are reimplemented from QScrollView * in order to ignore all mouseEvents on the viewport, so that the * parent can handle them. */ virtual void contentsMousePressEvent(QMouseEvent *); void mousePressEvent(QMouseEvent *) override; }; #endif diff --git a/src/knewpassworddialog.cpp b/src/knewpassworddialog.cpp index 9535600..165fda0 100644 --- a/src/knewpassworddialog.cpp +++ b/src/knewpassworddialog.cpp @@ -1,261 +1,256 @@ // vi: ts=8 sts=4 sw=4 /* This file is part of the KDE libraries Copyright (C) 1998 Pietro Iglio Copyright (C) 1999,2000 Geert Jansen Copyright (C) 2004,2005 Andrew Coles Copyright (C) 2007 Michaël Larouche This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "knewpassworddialog.h" -#include -#include #include -#include -#include #include #include -#include #include #include #include "ui_knewpassworddialog.h" class Q_DECL_HIDDEN KNewPasswordDialog::KNewPasswordDialogPrivate { public: KNewPasswordDialogPrivate(KNewPasswordDialog *parent) : q(parent) {} void init(); void _k_passwordStatusChanged(); void showMessageWidget(const QString &message, KMessageWidget::MessageType type); KNewPasswordDialog *q; QString pass; Ui::KNewPasswordDialog ui; }; void KNewPasswordDialog::KNewPasswordDialogPrivate::init() { ui.setupUi(q); QStyleOption option; option.initFrom(q); const int iconSize = q->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, q); ui.labelIcon->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-password")).pixmap(iconSize, iconSize)); ui.statusMsgWidget->hide(); connect(ui.pwdWidget, SIGNAL(passwordStatusChanged()), q, SLOT(_k_passwordStatusChanged())); } void KNewPasswordDialog::KNewPasswordDialogPrivate::_k_passwordStatusChanged() { switch (ui.pwdWidget->passwordStatus()) { case KNewPasswordWidget::PasswordTooShort: ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); //~ singular Password must be at least %n character long //~ plural Password must be at least %n characters long showMessageWidget(tr("Password must be at least %n character(s) long.", "", ui.pwdWidget->minimumPasswordLength()), KMessageWidget::Error); break; case KNewPasswordWidget::EmptyPasswordNotAllowed: ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); showMessageWidget(tr("Password is empty."), KMessageWidget::Warning); break; case KNewPasswordWidget::PasswordNotVerified: ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); showMessageWidget(tr("Passwords do not match."), KMessageWidget::Warning); break; case KNewPasswordWidget::WeakPassword: case KNewPasswordWidget::StrongPassword: ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); showMessageWidget(tr("Passwords match."), KMessageWidget::Positive); break; } } void KNewPasswordDialog::KNewPasswordDialogPrivate::showMessageWidget(const QString &message, KMessageWidget::MessageType type) { ui.statusMsgWidget->setText(message); ui.statusMsgWidget->setMessageType(type); ui.statusMsgWidget->animatedShow(); } /* * Password dialog. */ KNewPasswordDialog::KNewPasswordDialog(QWidget *parent) : QDialog(parent), d(new KNewPasswordDialogPrivate(this)) { d->init(); } KNewPasswordDialog::~KNewPasswordDialog() { delete d; } void KNewPasswordDialog::setPrompt(const QString &prompt) { d->ui.labelPrompt->setText(prompt); d->ui.labelPrompt->setMinimumSize(d->ui.labelPrompt->sizeHint()); } QString KNewPasswordDialog::prompt() const { return d->ui.labelPrompt->text(); } void KNewPasswordDialog::setPixmap(const QPixmap &pixmap) { d->ui.labelIcon->setPixmap(pixmap); d->ui.labelIcon->setFixedSize(d->ui.labelIcon->sizeHint()); } QPixmap KNewPasswordDialog::pixmap() const { return *d->ui.labelIcon->pixmap(); } bool KNewPasswordDialog::checkAndGetPassword(QString *pwd) { pwd->clear(); if (d->ui.pwdWidget->passwordStatus() == KNewPasswordWidget::WeakPassword) { QMessageBox::StandardButton selectedButton = QMessageBox::warning(this, tr("Low Password Strength"), tr("The password you have entered has a low strength. " "To improve the strength of " "the password, try:\n" " - using a longer password;\n" " - using a mixture of upper- and lower-case letters;\n" " - using numbers or symbols as well as letters.\n" "\n" "Would you like to use this password anyway?"), QMessageBox::Yes | QMessageBox::No); if (selectedButton == QMessageBox::No) { return false; } } if (!checkPassword(d->ui.pwdWidget->password())) { return false; } *pwd = d->ui.pwdWidget->password(); return true; } void KNewPasswordDialog::accept() { QString pwd; if (!checkAndGetPassword(&pwd)) { return; } d->pass = pwd; emit newPassword(d->pass); QDialog::accept(); } void KNewPasswordDialog::setAllowEmptyPasswords(bool allowed) { d->ui.pwdWidget->setAllowEmptyPasswords(allowed); } bool KNewPasswordDialog::allowEmptyPasswords() const { return d->ui.pwdWidget->allowEmptyPasswords(); } void KNewPasswordDialog::setMinimumPasswordLength(int minLength) { d->ui.pwdWidget->setMinimumPasswordLength(minLength); } int KNewPasswordDialog::minimumPasswordLength() const { return d->ui.pwdWidget->minimumPasswordLength(); } void KNewPasswordDialog::setMaximumPasswordLength(int maxLength) { d->ui.pwdWidget->setMaximumPasswordLength(maxLength); } int KNewPasswordDialog::maximumPasswordLength() const { return d->ui.pwdWidget->maximumPasswordLength(); } // reasonable password length code contributed by Steffen Mthing void KNewPasswordDialog::setReasonablePasswordLength(int reasonableLength) { d->ui.pwdWidget->setReasonablePasswordLength(reasonableLength); } int KNewPasswordDialog::reasonablePasswordLength() const { return d->ui.pwdWidget->reasonablePasswordLength(); } void KNewPasswordDialog::setPasswordStrengthWarningLevel(int warningLevel) { d->ui.pwdWidget->setPasswordStrengthWarningLevel(warningLevel); } int KNewPasswordDialog::passwordStrengthWarningLevel() const { return d->ui.pwdWidget->passwordStrengthWarningLevel(); } void KNewPasswordDialog::setBackgroundWarningColor(const QColor &color) { d->ui.pwdWidget->setBackgroundWarningColor(color); } QColor KNewPasswordDialog::backgroundWarningColor() const { return d->ui.pwdWidget->backgroundWarningColor(); } QString KNewPasswordDialog::password() const { return d->pass; } void KNewPasswordDialog::setRevealPasswordAvailable(bool reveal) { d->ui.pwdWidget->setRevealPasswordAvailable(reveal); } bool KNewPasswordDialog::isRevealPasswordAvailable() const { return d->ui.pwdWidget->isRevealPasswordAvailable(); } bool KNewPasswordDialog::checkPassword(const QString &) { return true; } #include "moc_knewpassworddialog.cpp" diff --git a/src/kpagedialog.cpp b/src/kpagedialog.cpp index c424917..55147d8 100644 --- a/src/kpagedialog.cpp +++ b/src/kpagedialog.cpp @@ -1,181 +1,180 @@ /* * This file is part of the KDE Libraries * Copyright (C) 1999-2001 Mirko Boehm (mirko@kde.org) and * Espen Sand (espen@kde.org) * Holger Freyther * 2005-2006 Olivier Goffart * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "kpagedialog.h" #include "kpagedialog_p.h" -#include #include KPageDialog::KPageDialog(QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags), d_ptr(new KPageDialogPrivate(this)) { Q_D(KPageDialog); d->mPageWidget = new KPageWidget(this); d->mPageWidget->layout()->setContentsMargins(0, 0, 0, 0); d->mButtonBox = new QDialogButtonBox(this); d->mButtonBox->setObjectName(QStringLiteral("buttonbox")); d->mButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); d->init(); } KPageDialog::KPageDialog(KPageWidget *widget, QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags), d_ptr(new KPageDialogPrivate(this)) { Q_D(KPageDialog); Q_ASSERT(widget); widget->setParent(this); d->mPageWidget = widget; d->mButtonBox = new QDialogButtonBox(this); d->mButtonBox->setObjectName(QStringLiteral("buttonbox")); d->mButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); d->init(); } KPageDialog::KPageDialog(KPageDialogPrivate &dd, KPageWidget *widget, QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags), d_ptr(&dd) { Q_D(KPageDialog); if (widget) { widget->setParent(this); d->mPageWidget = widget; } else { d->mPageWidget = new KPageWidget(this); } d->mButtonBox = new QDialogButtonBox(this); d->mButtonBox->setObjectName(QStringLiteral("buttonbox")); d->mButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); d->init(); } KPageDialog::~KPageDialog() { delete d_ptr; } void KPageDialog::setFaceType(FaceType faceType) { d_func()->mPageWidget->setFaceType(static_cast(faceType)); } KPageWidgetItem *KPageDialog::addPage(QWidget *widget, const QString &name) { return d_func()->mPageWidget->addPage(widget, name); } void KPageDialog::addPage(KPageWidgetItem *item) { d_func()->mPageWidget->addPage(item); } KPageWidgetItem *KPageDialog::insertPage(KPageWidgetItem *before, QWidget *widget, const QString &name) { return d_func()->mPageWidget->insertPage(before, widget, name); } void KPageDialog::insertPage(KPageWidgetItem *before, KPageWidgetItem *item) { d_func()->mPageWidget->insertPage(before, item); } KPageWidgetItem *KPageDialog::addSubPage(KPageWidgetItem *parent, QWidget *widget, const QString &name) { return d_func()->mPageWidget->addSubPage(parent, widget, name); } void KPageDialog::addSubPage(KPageWidgetItem *parent, KPageWidgetItem *item) { d_func()->mPageWidget->addSubPage(parent, item); } void KPageDialog::removePage(KPageWidgetItem *item) { d_func()->mPageWidget->removePage(item); } void KPageDialog::setCurrentPage(KPageWidgetItem *item) { d_func()->mPageWidget->setCurrentPage(item); } KPageWidgetItem *KPageDialog::currentPage() const { return d_func()->mPageWidget->currentPage(); } void KPageDialog::setStandardButtons(QDialogButtonBox::StandardButtons buttons) { d_func()->mButtonBox->setStandardButtons(buttons); } QPushButton *KPageDialog::button(QDialogButtonBox::StandardButton which) const { return d_func()->mButtonBox->button(which); } void KPageDialog::addActionButton(QAbstractButton *button) { d_func()->mButtonBox->addButton(button, QDialogButtonBox::ActionRole); } KPageWidget *KPageDialog::pageWidget() { return d_func()->mPageWidget; } void KPageDialog::setPageWidget(KPageWidget *widget) { delete d_func()->mPageWidget; d_func()->mPageWidget = widget; d_func()->init(); } const KPageWidget *KPageDialog::pageWidget() const { return d_func()->mPageWidget; } QDialogButtonBox *KPageDialog::buttonBox() { return d_func()->mButtonBox; } const QDialogButtonBox *KPageDialog::buttonBox() const { return d_func()->mButtonBox; } void KPageDialog::setButtonBox(QDialogButtonBox *box) { delete d_func()->mButtonBox; d_func()->mButtonBox = box; d_func()->init(); } diff --git a/src/kpageview.cpp b/src/kpageview.cpp index 48cd468..e0a2c25 100644 --- a/src/kpageview.cpp +++ b/src/kpageview.cpp @@ -1,505 +1,503 @@ /* This file is part of the KDE Libraries Copyright (C) 2006 Tobias Koenig (tokoe@kde.org) Copyright (C) 2007 Rafael Fernández López (ereslibre@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kpageview.h" #include "kpageview_p.h" #include "kpagemodel.h" #include "loggingcategory.h" #include #include #include -#include #include -#include #include void KPageViewPrivate::_k_rebuildGui() { // clean up old view Q_Q(KPageView); QModelIndex currentLastIndex; if (view && view->selectionModel()) { QObject::disconnect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(_k_pageSelected(QItemSelection,QItemSelection))); currentLastIndex = view->selectionModel()->currentIndex(); } delete view; view = q->createView(); Q_ASSERT(view); view->setSelectionBehavior(QAbstractItemView::SelectItems); view->setSelectionMode(QAbstractItemView::SingleSelection); if (model) { view->setModel(model); } // setup new view if (view->selectionModel()) { QObject::connect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(_k_pageSelected(QItemSelection,QItemSelection))); if (currentLastIndex.isValid()) { view->selectionModel()->setCurrentIndex(currentLastIndex, QItemSelectionModel::Select); } else if (model) { view->selectionModel()->setCurrentIndex(model->index(0, 0), QItemSelectionModel::Select); } } if (faceType == KPageView::Tabbed) { stack->setVisible(false); layout->removeWidget(stack); } else { layout->addWidget(stack, 2, 1); stack->setVisible(true); } titleWidget->setVisible(q->showPageHeader()); Qt::Alignment alignment = q->viewPosition(); if (alignment & Qt::AlignTop) { layout->addWidget(view, 2, 1); } else if (alignment & Qt::AlignRight) { layout->addWidget(view, 1, 2, 2, 1); } else if (alignment & Qt::AlignBottom) { layout->addWidget(view, 4, 1); } else if (alignment & Qt::AlignLeft) { layout->addWidget(view, 1, 0, 2, 1); } } void KPageViewPrivate::updateSelection() { /** * Select the first item in the view if not done yet. */ if (!model) { return; } if (!view || !view->selectionModel()) { return; } const QModelIndex index = view->selectionModel()->currentIndex(); if (!index.isValid()) { view->selectionModel()->setCurrentIndex(model->index(0, 0), QItemSelectionModel::Select); } } void KPageViewPrivate::cleanupPages() { /** * Remove all orphan pages from the stacked widget. */ const QList widgets = collectPages(); for (int i = 0; i < stack->count(); ++i) { QWidget *page = stack->widget(i); bool found = false; for (int j = 0; j < widgets.count(); ++j) { if (widgets[ j ] == page) { found = true; } } if (!found) { stack->removeWidget(page); } } } QList KPageViewPrivate::collectPages(const QModelIndex &parentIndex) { /** * Traverse through the model recursive and collect all widgets in * a list. */ QList retval; int rows = model->rowCount(parentIndex); for (int j = 0; j < rows; ++j) { const QModelIndex index = model->index(j, 0, parentIndex); retval.append(qvariant_cast(model->data(index, KPageModel::WidgetRole))); if (model->rowCount(index) > 0) { retval += collectPages(index); } } return retval; } KPageView::FaceType KPageViewPrivate::detectAutoFace() const { if (!model) { return KPageView::Plain; } /** * Check whether the model has sub pages. */ bool hasSubPages = false; const int count = model->rowCount(); for (int i = 0; i < count; ++i) { if (model->rowCount(model->index(i, 0)) > 0) { hasSubPages = true; break; } } if (hasSubPages) { return KPageView::Tree; } if (model->rowCount() > 1) { return KPageView::List; } return KPageView::Plain; } void KPageViewPrivate::_k_modelChanged() { if (!model) { return; } /** * If the face type is Auto, we rebuild the GUI whenever the layout * of the model changes. */ if (faceType == KPageView::Auto) { _k_rebuildGui(); // If you discover some crashes use the line below instead... //QTimer::singleShot(0, q, SLOT(_k_rebuildGui())); } /** * Set the stack to the minimum size of the largest widget. */ QSize size = stack->size(); const QList widgets = collectPages(); for (int i = 0; i < widgets.count(); ++i) { const QWidget *widget = widgets[ i ]; if (widget) { size = size.expandedTo(widget->minimumSizeHint()); } } stack->setMinimumSize(size); updateSelection(); } void KPageViewPrivate::_k_pageSelected(const QItemSelection &index, const QItemSelection &previous) { if (!model) { return; } // Return if the current Index is not valid if (index.indexes().size() != 1) { return; } QModelIndex currentIndex = index.indexes().first(); QModelIndex previousIndex; // The previous index can be invalid if (previous.indexes().size() == 1) { previousIndex = previous.indexes().first(); } if (faceType != KPageView::Tabbed) { QWidget *widget = qvariant_cast(model->data(currentIndex, KPageModel::WidgetRole)); if (widget) { if (stack->indexOf(widget) == -1) { // not included yet stack->addWidget(widget); } stack->setCurrentWidget(widget); } else { stack->setCurrentWidget(defaultWidget); } updateTitleWidget(currentIndex); } Q_Q(KPageView); emit q->currentPageChanged(currentIndex, previousIndex); } void KPageViewPrivate::updateTitleWidget(const QModelIndex &index) { Q_Q(KPageView); const bool headerVisible = model->data(index, KPageModel::HeaderVisibleRole).toBool(); if (!headerVisible) { titleWidget->setVisible(false); return; } QString header = model->data(index, KPageModel::HeaderRole).toString(); if (header.isNull()) { //TODO KDE5 remove that ugly logic, see also doxy-comments in KPageWidgetItem::setHeader() header = model->data(index, Qt::DisplayRole).toString(); } titleWidget->setText(header); titleWidget->setVisible(q->showPageHeader()); } void KPageViewPrivate::_k_dataChanged(const QModelIndex &, const QModelIndex &) { /** * When data has changed we update the header and icon for the currently selected * page. */ if (!view) { return; } QModelIndex index = view->selectionModel()->currentIndex(); if (!index.isValid()) { return; } updateTitleWidget(index); } KPageViewPrivate::KPageViewPrivate(KPageView *_parent) : q_ptr(_parent), model(nullptr), faceType(KPageView::Auto), layout(nullptr), stack(nullptr), titleWidget(nullptr), view(nullptr) { } void KPageViewPrivate::init() { Q_Q(KPageView); layout = new QGridLayout(q); stack = new KPageStackedWidget(q); titleWidget = new KTitleWidget(q); QPixmap emptyPixmap(22, 22); emptyPixmap.fill(Qt::transparent); titleWidget->setPixmap(emptyPixmap); layout->addWidget(titleWidget, 1, 1); layout->addWidget(stack, 2, 1); defaultWidget = new QWidget(q); stack->addWidget(defaultWidget); // stack should use most space layout->setColumnStretch(1, 1); layout->setRowStretch(2, 1); } /** * KPageView Implementation */ KPageView::KPageView(QWidget *parent) : QWidget(parent), d_ptr(new KPageViewPrivate(this)) { d_ptr->init(); } KPageView::KPageView(KPageViewPrivate &dd, QWidget *parent) : QWidget(parent), d_ptr(&dd) { d_ptr->init(); } KPageView::~KPageView() { delete d_ptr; } void KPageView::setModel(QAbstractItemModel *model) { Q_D(KPageView); // clean up old model if (d->model) { disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_k_modelChanged())); disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(_k_dataChanged(QModelIndex,QModelIndex))); } d->model = model; if (d->model) { connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_k_modelChanged())); connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(_k_dataChanged(QModelIndex,QModelIndex))); // set new model in navigation view if (d->view) { d->view->setModel(model); } } d->_k_rebuildGui(); } QAbstractItemModel *KPageView::model() const { return d_func()->model; } void KPageView::setFaceType(FaceType faceType) { Q_D(KPageView); d->faceType = faceType; d->_k_rebuildGui(); } KPageView::FaceType KPageView::faceType() const { return d_func()->faceType; } void KPageView::setCurrentPage(const QModelIndex &index) { Q_D(KPageView); if (!d->view || !d->view->selectionModel()) { return; } d->view->selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent); } QModelIndex KPageView::currentPage() const { Q_D(const KPageView); if (!d->view || !d->view->selectionModel()) { return QModelIndex(); } return d->view->selectionModel()->currentIndex(); } void KPageView::setItemDelegate(QAbstractItemDelegate *delegate) { Q_D(KPageView); if (d->view) { d->view->setItemDelegate(delegate); } } QAbstractItemDelegate *KPageView::itemDelegate() const { Q_D(const KPageView); if (d->view) { return d->view->itemDelegate(); } else { return nullptr; } } void KPageView::setDefaultWidget(QWidget *widget) { Q_D(KPageView); Q_ASSERT(widget); bool isCurrent = (d->stack->currentIndex() == d->stack->indexOf(d->defaultWidget)); // remove old default widget d->stack->removeWidget(d->defaultWidget); delete d->defaultWidget; // add new default widget d->defaultWidget = widget; d->stack->addWidget(d->defaultWidget); if (isCurrent) { d->stack->setCurrentWidget(d->defaultWidget); } } QAbstractItemView *KPageView::createView() { Q_D(KPageView); if (d->faceType == Auto) { const FaceType faceType = d->detectAutoFace(); if (faceType == Plain) { return new KDEPrivate::KPagePlainView(this); } else if (faceType == List) { return new KDEPrivate::KPageListView(this); } else if (faceType == Tree) { return new KDEPrivate::KPageTreeView(this); } else { // should never happen return nullptr; } } else if (d->faceType == Plain) { return new KDEPrivate::KPagePlainView(this); } else if (d->faceType == List) { return new KDEPrivate::KPageListView(this); } else if (d->faceType == Tree) { return new KDEPrivate::KPageTreeView(this); } else if (d->faceType == Tabbed) { return new KDEPrivate::KPageTabbedView(this); } else { return nullptr; } } bool KPageView::showPageHeader() const { Q_D(const KPageView); FaceType faceType = d->faceType; if (faceType == Auto) { faceType = d->detectAutoFace(); } if (faceType == Tabbed) { return false; } else { return !d->titleWidget->text().isEmpty(); } } Qt::Alignment KPageView::viewPosition() const { Q_D(const KPageView); FaceType faceType = d->faceType; if (faceType == Auto) { faceType = d->detectAutoFace(); } if (faceType == Plain || faceType == Tabbed) { return Qt::AlignTop; } else { return Qt::AlignLeft; } } #include "moc_kpageview.cpp" diff --git a/src/kpageview_p.h b/src/kpageview_p.h index d3af4b3..7ca8205 100644 --- a/src/kpageview_p.h +++ b/src/kpageview_p.h @@ -1,246 +1,245 @@ /* This file is part of the KDE Libraries Copyright (C) 2006 Tobias Koenig (tokoe@kde.org) Copyright (C) 2007 Rafael Fernández López (ereslibre@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KPAGEVIEW_P_H #define KPAGEVIEW_P_H #include "kpageview.h" #include #include #include #include #include -#include #include #include class KPageStackedWidget : public QStackedWidget { Q_OBJECT public: explicit KPageStackedWidget(QWidget *parent = nullptr) : QStackedWidget(parent) { } void setMinimumSize(const QSize &size) { mMinimumSize = size; } QSize minimumSizeHint() const override { return mMinimumSize.expandedTo(QStackedWidget::minimumSizeHint()); } private: QSize mMinimumSize; }; class KPageViewPrivate { Q_DECLARE_PUBLIC(KPageView) protected: KPageViewPrivate(KPageView *); KPageView *q_ptr; // data QAbstractItemModel *model; KPageView::FaceType faceType; // gui QGridLayout *layout; KPageStackedWidget *stack; KTitleWidget *titleWidget; QWidget *defaultWidget; QAbstractItemView *view; void updateTitleWidget(const QModelIndex &index); void updateSelection(); void cleanupPages(); QList collectPages(const QModelIndex &parent = QModelIndex()); KPageView::FaceType detectAutoFace() const; // private slots void _k_rebuildGui(); void _k_modelChanged(); void _k_dataChanged(const QModelIndex &, const QModelIndex &); void _k_pageSelected(const QItemSelection &, const QItemSelection &); private: void init(); }; namespace KDEPrivate { class KPageListViewDelegate; class KPageListViewProxy; class KPagePlainView : public QAbstractItemView { Q_OBJECT public: explicit KPagePlainView(QWidget *parent = nullptr); QModelIndex indexAt(const QPoint &point) const override; void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; QRect visualRect(const QModelIndex &index) const override; protected: QModelIndex moveCursor(QAbstractItemView::CursorAction, Qt::KeyboardModifiers) override; int horizontalOffset() const override; int verticalOffset() const override; bool isIndexHidden(const QModelIndex &) const override; void setSelection(const QRect &, QFlags) override; QRegion visualRegionForSelection(const QItemSelection &) const override; }; class KPageListView : public QListView { Q_OBJECT public: explicit KPageListView(QWidget *parent = nullptr); ~KPageListView() override; void setModel(QAbstractItemModel *model) override; protected: void changeEvent(QEvent *event) override; private Q_SLOTS: void updateWidth(); }; class KPageTreeView : public QTreeView { Q_OBJECT public: explicit KPageTreeView(QWidget *parent = nullptr); void setModel(QAbstractItemModel *model) override; private Q_SLOTS: void updateWidth(); private: void expandItems(const QModelIndex &index = QModelIndex()); }; class KPageTabbedView : public QAbstractItemView { Q_OBJECT public: explicit KPageTabbedView(QWidget *parent = nullptr); ~KPageTabbedView() override; void setModel(QAbstractItemModel *model) override; QModelIndex indexAt(const QPoint &point) const override; void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; QRect visualRect(const QModelIndex &index) const override; QSize minimumSizeHint() const override; protected: QModelIndex moveCursor(QAbstractItemView::CursorAction, Qt::KeyboardModifiers) override; int horizontalOffset() const override; int verticalOffset() const override; bool isIndexHidden(const QModelIndex &) const override; void setSelection(const QRect &, QFlags) override; QRegion visualRegionForSelection(const QItemSelection &) const override; private Q_SLOTS: void currentPageChanged(int); void layoutChanged(); void dataChanged(const QModelIndex &, const QModelIndex &, const QVector &roles) override; private: QTabWidget *mTabWidget; }; class KPageListViewDelegate : public QAbstractItemDelegate { Q_OBJECT public: explicit KPageListViewDelegate(QObject *parent = nullptr); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: void drawFocus(QPainter *, const QStyleOptionViewItem &, const QRect &) const; }; /** * We need this proxy model to map the leaves of a tree-like model * to a one-level list model. */ class KPageListViewProxy : public QAbstractProxyModel { Q_OBJECT public: explicit KPageListViewProxy(QObject *parent = nullptr); ~KPageListViewProxy() override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &) const override; QVariant data(const QModelIndex &index, int role) const override; QModelIndex mapFromSource(const QModelIndex &index) const override; QModelIndex mapToSource(const QModelIndex &index) const override; public Q_SLOTS: void rebuildMap(); private: void addMapEntry(const QModelIndex &); QList mList; }; class SelectionModel : public QItemSelectionModel { Q_OBJECT public: SelectionModel(QAbstractItemModel *model, QObject *parent); public Q_SLOTS: void clear() override; void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) override; void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override; }; } #endif diff --git a/src/kpassworddialog.cpp b/src/kpassworddialog.cpp index 74920a2..fdef92b 100644 --- a/src/kpassworddialog.cpp +++ b/src/kpassworddialog.cpp @@ -1,417 +1,416 @@ /* This file is part of the KDE libraries Copyright (C) 2000 David Faure Copyright (C) 2007 Olivier Goffart This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kpassworddialog.h" #include #include #include #include #include #include #include -#include #include #include #include "ui_kpassworddialog.h" /** @internal */ class Q_DECL_HIDDEN KPasswordDialog::KPasswordDialogPrivate { public: KPasswordDialogPrivate(KPasswordDialog *q) : q(q), userEditCombo(nullptr), pixmapLabel(nullptr), commentRow(0) {} void actuallyAccept(); void activated(const QString &userName); void updateFields(); void init(); KPasswordDialog *q; Ui_KPasswordDialog ui; QMap knownLogins; QComboBox *userEditCombo; QLabel *pixmapLabel; KPasswordDialogFlags m_flags; unsigned int commentRow; }; KPasswordDialog::KPasswordDialog(QWidget *parent, const KPasswordDialogFlags &flags) : QDialog(parent), d(new KPasswordDialogPrivate(this)) { setWindowTitle(tr("Password")); setWindowIcon(QIcon::fromTheme(QStringLiteral("dialog-password"), windowIcon())); d->m_flags = flags; d->init(); } KPasswordDialog::~KPasswordDialog() { delete d; } void KPasswordDialog::KPasswordDialogPrivate::updateFields() { if (m_flags & KPasswordDialog::UsernameReadOnly) { ui.userEdit->setReadOnly(true); ui.credentialsGroup->setFocusProxy(ui.passEdit); } ui.domainEdit->setReadOnly((m_flags & KPasswordDialog::DomainReadOnly)); ui.credentialsGroup->setEnabled(!q->anonymousMode()); } void KPasswordDialog::KPasswordDialogPrivate::init() { ui.setupUi(q); ui.buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); ui.errorMessage->setHidden(true); // Row 4: Username field if (m_flags & KPasswordDialog::ShowUsernameLine) { ui.userEdit->setFocus(); ui.credentialsGroup->setFocusProxy(ui.userEdit); QObject::connect(ui.userEdit, &QLineEdit::returnPressed, ui.passEdit, QOverload<>::of(&QWidget::setFocus)); } else { ui.userNameLabel->hide(); ui.userEdit->hide(); ui.domainLabel->hide(); ui.domainEdit->hide(); ui.passEdit->setFocus(); ui.credentialsGroup->setFocusProxy(ui.passEdit); ui.prompt->setText(QApplication::translate("KPasswordDialog", "Supply a password below.")); } if (!(m_flags & KPasswordDialog::ShowAnonymousLoginCheckBox)) { ui.anonymousRadioButton->hide(); ui.usePasswordButton->hide(); } if (!(m_flags & KPasswordDialog::ShowDomainLine)) { ui.domainLabel->hide(); ui.domainEdit->hide(); } if (!(m_flags & KPasswordDialog::ShowKeepPassword)) { ui.keepCheckBox->hide(); } updateFields(); QRect desktop = QApplication::desktop()->screenGeometry(q->topLevelWidget()); q->setMinimumWidth(qMin(1000, qMax(q->sizeHint().width(), desktop.width() / 4))); QStyleOption option; option.initFrom(q); const int iconSize = q->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, q); q->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-password")).pixmap(iconSize)); } void KPasswordDialog::setPixmap(const QPixmap &pixmap) { if (!d->pixmapLabel) { d->pixmapLabel = new QLabel(this); d->pixmapLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); d->ui.hboxLayout->insertWidget(0, d->pixmapLabel); } d->pixmapLabel->setPixmap(pixmap); } QPixmap KPasswordDialog::pixmap() const { if (!d->pixmapLabel) { return QPixmap(); } return *d->pixmapLabel->pixmap(); } void KPasswordDialog::setUsername(const QString &user) { d->ui.userEdit->setText(user); if (user.isEmpty()) { return; } d->activated(user); if (d->ui.userEdit->isVisibleTo(this)) { d->ui.passEdit->setFocus(); } } QString KPasswordDialog::username() const { return d->ui.userEdit->text(); } QString KPasswordDialog::password() const { return d->ui.passEdit->password(); } void KPasswordDialog::setDomain(const QString &domain) { d->ui.domainEdit->setText(domain); } QString KPasswordDialog::domain() const { return d->ui.domainEdit->text(); } void KPasswordDialog::setAnonymousMode(bool anonymous) { if (anonymous && !(d->m_flags & KPasswordDialog::ShowAnonymousLoginCheckBox)) { // This is an error case, but we can at least let user see what's about // to happen if they proceed. d->ui.anonymousRadioButton->setVisible(true); d->ui.usePasswordButton->setVisible(true); d->ui.usePasswordButton->setEnabled(false); } d->ui.anonymousRadioButton->setChecked(anonymous); } bool KPasswordDialog::anonymousMode() const { return d->ui.anonymousRadioButton->isChecked(); } void KPasswordDialog::setKeepPassword(bool b) { d->ui.keepCheckBox->setChecked(b); } bool KPasswordDialog::keepPassword() const { return d->ui.keepCheckBox->isChecked(); } void KPasswordDialog::addCommentLine(const QString &label, const QString &comment) { int gridMarginLeft, gridMarginTop, gridMarginRight, gridMarginBottom; d->ui.formLayout->getContentsMargins(&gridMarginLeft, &gridMarginTop, &gridMarginRight, &gridMarginBottom); int spacing = d->ui.formLayout->horizontalSpacing(); if (spacing < 0) { // same inter-column spacing for all rows, see comment in qformlayout.cpp spacing = style()->combinedLayoutSpacing(QSizePolicy::Label, QSizePolicy::LineEdit, Qt::Horizontal, nullptr, this); } QLabel *c = new QLabel(comment, this); c->setWordWrap(true); d->ui.formLayout->insertRow(d->commentRow, label, c); ++d->commentRow; // cycle through column 0 widgets and see the max width so we can set the minimum height of // column 2 wordwrapable labels int firstColumnWidth = 0; for (int i = 0; i < d->ui.formLayout->rowCount(); ++i) { QLayoutItem *li = d->ui.formLayout->itemAt(i, QFormLayout::LabelRole); if (li) { QWidget *w = li->widget(); if (w && !w->isHidden()) { firstColumnWidth = qMax(firstColumnWidth, w->sizeHint().width()); } } } for (int i = 0; i < d->ui.formLayout->rowCount(); ++i) { QLayoutItem *li = d->ui.formLayout->itemAt(i, QFormLayout::FieldRole); if (li) { QLabel *l = qobject_cast(li->widget()); if (l && l->wordWrap()) { const int marginHint = style()->pixelMetric(QStyle::PM_DefaultChildMargin); int w = sizeHint().width() - firstColumnWidth - (2 * marginHint) - gridMarginLeft - gridMarginRight - spacing; l->setMinimumSize(w, l->heightForWidth(w)); } } } } void KPasswordDialog::showErrorMessage(const QString &message, const ErrorType type) { d->ui.errorMessage->setText(message, KTitleWidget::ErrorMessage); QFont bold = font(); bold.setBold(true); switch (type) { case PasswordError: d->ui.passwordLabel->setFont(bold); d->ui.passEdit->clear(); d->ui.passEdit->setFocus(); break; case UsernameError: if (d->ui.userEdit->isVisibleTo(this)) { d->ui.userNameLabel->setFont(bold); d->ui.userEdit->setFocus(); } break; case DomainError: if (d->ui.domainEdit->isVisibleTo(this)) { d->ui.domainLabel->setFont(bold); d->ui.domainEdit->setFocus(); } break; case FatalError: d->ui.userNameLabel->setEnabled(false); d->ui.userEdit->setEnabled(false); d->ui.passwordLabel->setEnabled(false); d->ui.passEdit->setEnabled(false); d->ui.keepCheckBox->setEnabled(false); d->ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); break; default: break; } adjustSize(); } void KPasswordDialog::setPrompt(const QString &prompt) { d->ui.prompt->setText(prompt); d->ui.prompt->setWordWrap(true); const int marginHint = style()->pixelMetric(QStyle::PM_DefaultChildMargin); d->ui.prompt->setMinimumHeight(d->ui.prompt->heightForWidth(width() - (2 * marginHint))); } QString KPasswordDialog::prompt() const { return d->ui.prompt->text(); } void KPasswordDialog::setPassword(const QString &p) { d->ui.passEdit->setPassword(p); } void KPasswordDialog::setUsernameReadOnly(bool readOnly) { d->ui.userEdit->setReadOnly(readOnly); if (readOnly && d->ui.userEdit->hasFocus()) { d->ui.passEdit->setFocus(); } } void KPasswordDialog::setKnownLogins(const QMap &knownLogins) { const int nr = knownLogins.count(); if (nr == 0) { return; } if (nr == 1) { d->ui.userEdit->setText(knownLogins.begin().key()); setPassword(knownLogins.begin().value()); return; } Q_ASSERT(!d->ui.userEdit->isReadOnly()); if (!d->userEditCombo) { int row = -1; QFormLayout::ItemRole userEditRole = QFormLayout::FieldRole; d->ui.formLayout->getWidgetPosition(d->ui.userEdit, &row, &userEditRole); d->ui.formLayout->removeWidget(d->ui.userEdit); delete d->ui.userEdit; d->userEditCombo = new QComboBox(d->ui.credentialsGroup); d->userEditCombo->setEditable(true); d->ui.userEdit = d->userEditCombo->lineEdit(); d->ui.userNameLabel->setBuddy(d->userEditCombo); d->ui.formLayout->setWidget(row > -1 ? row : 0, userEditRole, d->userEditCombo); setTabOrder(d->ui.userEdit, d->ui.anonymousRadioButton); setTabOrder(d->ui.anonymousRadioButton, d->ui.domainEdit); setTabOrder(d->ui.domainEdit, d->ui.passEdit); setTabOrder(d->ui.passEdit, d->ui.keepCheckBox); connect(d->ui.userEdit, &QLineEdit::returnPressed, d->ui.passEdit, QOverload<>::of(&QWidget::setFocus)); } d->knownLogins = knownLogins; d->userEditCombo->addItems(knownLogins.keys()); d->userEditCombo->setFocus(); connect(d->userEditCombo, SIGNAL(activated(QString)), this, SLOT(activated(QString))); } void KPasswordDialog::KPasswordDialogPrivate::activated(const QString &userName) { QMap::ConstIterator it = knownLogins.constFind(userName); if (it != knownLogins.constEnd()) { q->setPassword(it.value()); } } void KPasswordDialog::accept() { if (!d->ui.errorMessage->isHidden()) { d->ui.errorMessage->setText(QString()); } // reset the font in case we had an error previously if (!d->ui.passwordLabel->isHidden()) { d->ui.passwordLabel->setFont(font()); d->ui.userNameLabel->setFont(font()); } // we do this to allow the error message, if any, to go away // checkPassword() may block for a period of time QTimer::singleShot(0, this, [this] { d->actuallyAccept(); }); } void KPasswordDialog::KPasswordDialogPrivate::actuallyAccept() { if (!q->checkPassword()) { return; } bool keep = ui.keepCheckBox->isVisibleTo(q) && ui.keepCheckBox->isChecked(); emit q->gotPassword(q->password(), keep); if (ui.userEdit->isVisibleTo(q)) { emit q->gotUsernameAndPassword(q->username(), q->password(), keep); } q->QDialog::accept(); } bool KPasswordDialog::checkPassword() { return true; } QDialogButtonBox *KPasswordDialog::buttonBox() const { return d->ui.buttonBox; } #include "moc_kpassworddialog.cpp" diff --git a/src/kpassworddialog.h b/src/kpassworddialog.h index fcb5a7c..5bf0c3c 100644 --- a/src/kpassworddialog.h +++ b/src/kpassworddialog.h @@ -1,322 +1,321 @@ /* This file is part of the KDE libraries Copyright (C) 2000 David Faure Copyright (C) 2000 Dawit Alemayehu Copyright (C) 2007 Olivier Goffart This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KPASSWORDDIALOG_H #define KPASSWORDDIALOG_H #include #include -#include #include /** * @class KPasswordDialog kpassworddialog.h KPasswordDialog * * A dialog for requesting a password and optionaly a login from the end user. * * \section usage Usage Example * * Requesting a simple password, asynchronous * * \code * KPasswordDialog *dlg = new KPasswordDialog( parent ); * dlg->setPrompt(i18n("Enter a password")); * connect( dlg, SIGNAL( gotPassword( const QString& , bool ) ) , this, SLOT( setPassword( const QString &) ) ); * connect( dlg, SIGNAL( rejected() ) , this, SLOT( slotCancel() ) ); * dlg->show(); * \endcode * * Requesting a login and a password, synchronous * * \code * KPasswordDialog dlg(parent, KPasswordDialog::ShowUsernameLine); * dlg.setPrompt(i18n("Enter a login and a password")); * if( !dlg.exec() ) * return; //the user canceled * use( dlg.username() , dlg.password() ); * \endcode * * \image html kpassworddialog.png "KPasswordDialog" * * @short dialog for requesting login and password from the end user */ class KWIDGETSADDONS_EXPORT KPasswordDialog : public QDialog { Q_OBJECT public: enum KPasswordDialogFlag { NoFlags = 0x00, /** * If this flag is set, the "keep this password" checkbox will been shown, * otherwise, it will not be shown and keepPassword will have no effect */ ShowKeepPassword = 0x01, /** * If this flag is set, there will be an additional line to let the user enter his login. * otherwise, only the password line will be shown. */ ShowUsernameLine = 0x02, /** * If this flag is set, the login lineedit will be in read only mode. */ UsernameReadOnly = 0x04, /** * If this flag is set, the Anonymous Login checkbox will be displayed * @since 4.1 */ ShowAnonymousLoginCheckBox = 0x08, /** * If this flag is set, there will be an additional line to let the user enter the domain. * @since 4.1 */ ShowDomainLine = 0x10, /** * If this flag is set, the domain lineedit will be in read only mode. * @since 4.1 */ DomainReadOnly = 0x20 }; Q_DECLARE_FLAGS(KPasswordDialogFlags, KPasswordDialogFlag) enum ErrorType { UnknownError = 0, /** * A problem with the user name as entered **/ UsernameError, /** * Incorrect password */ PasswordError, /** * Error preventing further attempts, will result in disabling most of the interface */ FatalError, /** * A problem with the domain as entered * @since 4.1 **/ DomainError }; /** * create a password dialog * * @param parent the parent widget * @param flags a set of KPasswordDialogFlag flags */ explicit KPasswordDialog(QWidget *parent = nullptr, const KPasswordDialogFlags &flags = KPasswordDialog::NoFlags); /** * Destructor */ ~KPasswordDialog() override; /** * Sets the prompt to show to the user. * @param prompt instructional text to be shown. */ void setPrompt(const QString &prompt); /** * Returns the prompt */ QString prompt() const; /** * set an image that appears next to the prompt. */ void setPixmap(const QPixmap &); /** * */ QPixmap pixmap() const; /** * Adds a comment line to the dialog. * * This function allows you to add one additional comment * line to this widget. Calling this function after a * comment has already been added will not have any effect. * * @param label label for comment (ex:"Command:") * @param comment the actual comment text. */ void addCommentLine(const QString &label, const QString &comment); /** * Shows an error message in the dialog box. Prevents having to show a dialog-on-a-dialog. * * @param message the error message to show */ void showErrorMessage(const QString &message, const ErrorType type = PasswordError); /** * Returns the password entered by the user. * @return the password */ QString password() const; /** * set the default username. */ void setUsername(const QString &); /** * Returns the username entered by the user. * @return the user name */ QString username() const; /** * set the default domain. * @since 4.1 */ void setDomain(const QString &); /** * Returns the domain entered by the user. * @return the domain name * @since 4.1 */ QString domain() const; /** * set anonymous mode (all other fields will be grayed out) * @since 4.1 */ void setAnonymousMode(bool anonymous); /** * @return anonymous mode has been selected. * @since 4.1 */ bool anonymousMode() const; /** * Determines whether supplied authorization should * persist even after the application has been closed. * * this is set with the check password checkbox is the ShowKeepCheckBox flag * is set in the constructor, if it is not set, this function return false * * @return true to keep the password */ bool keepPassword() const; /** * Check or uncheck the "keep password" checkbox. * This can be used to check it before showing the dialog, to tell * the user that the password is stored already (e.g. in the wallet). * enableKeep must have been set to true in the constructor. * * has only effect if ShowKeepCheckBox is set in the constructor */ void setKeepPassword(bool b); /** * Sets the username field read-only and sets the * focus to the password field. * * this can also be set by passing UsernameReadOnly as flag in the constructor * * @param readOnly true to set the user field to read-only */ void setUsernameReadOnly(bool readOnly); /** * Presets the password. * If the password is not empty, the ability to show the password will not be available. * @param password the password to set */ void setPassword(const QString &password); /** * Presets a number of login+password pairs that the user can choose from. * The passwords can be empty if you simply want to offer usernames to choose from. * * This require the flag ShowUnernameLine to be set in the constructoe, and not the flag UsernameReadOnly * @param knownLogins map of known logins: the keys are usernames, the values are passwords. */ void setKnownLogins(const QMap &knownLogins); /** * @internal */ void accept() override; /** * Returns the button box used in the dialog. * This can be used to add new buttons. * * @return the button box * * @since 5.0 */ QDialogButtonBox *buttonBox() const; Q_SIGNALS: /** * emitted when the dialog has been accepted * @param password the entered password * @param keep true if the "remember password" checkbox was checked, false otherwise. false if ShowKeepPassword was not set in the constructor */ void gotPassword(const QString &password, bool keep); /** * emitted when the dialog has been accepted, and ShowUsernameLine was set on the constructor * @param username the entered username * @param password the entered password * @param keep true if the "remember password" checkbox was checked, false otherwise. false if ShowKeepPassword was not set in the constructor */ void gotUsernameAndPassword(const QString &username, const QString &password, bool keep); protected: /** * Virtual function that can be overridden to provide password * checking in derived classes. It should return @p true if the * password is valid, @p false otherwise. */ virtual bool checkPassword(); private: Q_PRIVATE_SLOT(d, void actuallyAccept()) Q_PRIVATE_SLOT(d, void activated(const QString &userName)) Q_PRIVATE_SLOT(d, void updateFields()) private: class KPasswordDialogPrivate; friend class KPasswordDialogPrivate; KPasswordDialogPrivate *const d; Q_DISABLE_COPY(KPasswordDialog) }; Q_DECLARE_OPERATORS_FOR_FLAGS(KPasswordDialog::KPasswordDialogFlags) #endif diff --git a/src/kpixmapregionselectorwidget.cpp b/src/kpixmapregionselectorwidget.cpp index 2d9b8af..7eab5da 100644 --- a/src/kpixmapregionselectorwidget.cpp +++ b/src/kpixmapregionselectorwidget.cpp @@ -1,511 +1,512 @@ /* This file is part of the KDE libraries Copyright (C) 2004 Antonio Larrosa #include #include #include #include -#include #include #include #include #include #include +#include +#include class Q_DECL_HIDDEN KPixmapRegionSelectorWidget::Private { public: Private(KPixmapRegionSelectorWidget *q): q(q) {} KPixmapRegionSelectorWidget *q; /** * Recalculates the pixmap that is shown based on the current selected area, * the original image, etc. */ void updatePixmap(); QRect calcSelectionRectangle(const QPoint &startPoint, const QPoint &endPoint); enum CursorState { None = 0, Resizing, Moving }; CursorState m_state; QPixmap m_unzoomedPixmap; QPixmap m_originalPixmap; QPixmap m_linedPixmap; QRect m_selectedRegion; QLabel *m_label; QPoint m_tempFirstClick; double m_forcedAspectRatio; int m_maxWidth, m_maxHeight; double m_zoomFactor; QRubberBand *m_rubberBand; }; KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget(QWidget *parent) : QWidget(parent), d(new Private(this)) { QHBoxLayout *hboxLayout = new QHBoxLayout(this); hboxLayout->addStretch(); QVBoxLayout *vboxLayout = new QVBoxLayout(); hboxLayout->addItem(vboxLayout); vboxLayout->addStretch(); d->m_label = new QLabel(this); d->m_label->setAttribute(Qt::WA_NoSystemBackground, true); //setBackgroundMode( Qt::NoBackground ); d->m_label->installEventFilter(this); vboxLayout->addWidget(d->m_label); vboxLayout->addStretch(); hboxLayout->addStretch(); d->m_forcedAspectRatio = 0; d->m_zoomFactor = 1.0; d->m_rubberBand = new QRubberBand(QRubberBand::Rectangle, d->m_label); d->m_rubberBand->hide(); } KPixmapRegionSelectorWidget::~KPixmapRegionSelectorWidget() { delete d; } QPixmap KPixmapRegionSelectorWidget::pixmap() const { return d->m_unzoomedPixmap; } void KPixmapRegionSelectorWidget::setPixmap(const QPixmap &pixmap) { Q_ASSERT(!pixmap.isNull()); //This class isn't designed to deal with null pixmaps. d->m_originalPixmap = pixmap; d->m_unzoomedPixmap = pixmap; d->m_label->setPixmap(pixmap); resetSelection(); } void KPixmapRegionSelectorWidget::resetSelection() { d->m_selectedRegion = d->m_originalPixmap.rect(); d->m_rubberBand->hide(); d->updatePixmap(); } QRect KPixmapRegionSelectorWidget::selectedRegion() const { return d->m_selectedRegion; } void KPixmapRegionSelectorWidget::setSelectedRegion(const QRect &rect) { if (!rect.isValid()) { resetSelection(); } else { d->m_selectedRegion = rect; d->updatePixmap(); } } void KPixmapRegionSelectorWidget::Private::updatePixmap() { Q_ASSERT(!m_originalPixmap.isNull()); if (m_originalPixmap.isNull()) { m_label->setPixmap(m_originalPixmap); return; } if (m_selectedRegion.width() > m_originalPixmap.width()) { m_selectedRegion.setWidth(m_originalPixmap.width()); } if (m_selectedRegion.height() > m_originalPixmap.height()) { m_selectedRegion.setHeight(m_originalPixmap.height()); } QPainter painter; if (m_linedPixmap.isNull()) { m_linedPixmap = m_originalPixmap; QPainter p(&m_linedPixmap); p.setCompositionMode(QPainter::CompositionMode_SourceAtop); p.fillRect(m_linedPixmap.rect(), QColor(0, 0, 0, 100)); } QPixmap pixmap = m_linedPixmap; painter.begin(&pixmap); painter.drawPixmap(m_selectedRegion.topLeft(), m_originalPixmap, m_selectedRegion); painter.end(); m_label->setPixmap(pixmap); qApp->sendPostedEvents(nullptr, QEvent::LayoutRequest); if (m_selectedRegion == m_originalPixmap.rect()) {//d->m_label->rect()) //### CHECK! m_rubberBand->hide(); } else { m_rubberBand->setGeometry(QRect(m_selectedRegion.topLeft(), m_selectedRegion.size())); /* m_rubberBand->setGeometry(QRect(m_label -> mapToGlobal(m_selectedRegion.topLeft()), m_selectedRegion.size())); */ if (m_state != None) { m_rubberBand->show(); } } } QMenu *KPixmapRegionSelectorWidget::createPopupMenu() { QMenu *popup = new QMenu(this); popup->setObjectName(QStringLiteral("PixmapRegionSelectorPopup")); popup->addSection(tr("Image Operations")); popup->addAction(QIcon::fromTheme(QStringLiteral("object-rotate-right")), tr("&Rotate Clockwise"), this, &KPixmapRegionSelectorWidget::rotateClockwise); popup->addAction(QIcon::fromTheme(QStringLiteral("object-rotate-left")), tr("Rotate &Counterclockwise"), this, &KPixmapRegionSelectorWidget::rotateCounterclockwise); /* I wonder if it would be appropriate to have here an "Open with..." option to edit the image (antlarr) */ return popup; } void KPixmapRegionSelectorWidget::rotate(RotateDirection direction) { int w = d->m_originalPixmap.width(); int h = d->m_originalPixmap.height(); QImage img = d->m_unzoomedPixmap.toImage(); if (direction == Rotate90) { img = img.transformed(QTransform().rotate(90.0)); } else if (direction == Rotate180) { img = img.transformed(QTransform().rotate(180.0)); } else { img = img.transformed(QTransform().rotate(270.0)); } d->m_unzoomedPixmap = QPixmap::fromImage(img); img = d->m_originalPixmap.toImage(); if (direction == Rotate90) { img = img.transformed(QTransform().rotate(90.0)); } else if (direction == Rotate180) { img = img.transformed(QTransform().rotate(180.0)); } else { img = img.transformed(QTransform().rotate(270.0)); } d->m_originalPixmap = QPixmap::fromImage(img); d->m_linedPixmap = QPixmap(); if (d->m_forcedAspectRatio > 0 && d->m_forcedAspectRatio != 1) { resetSelection(); } else { switch (direction) { case (Rotate90): { int x = h - d->m_selectedRegion.y() - d->m_selectedRegion.height(); int y = d->m_selectedRegion.x(); d->m_selectedRegion.setRect(x, y, d->m_selectedRegion.height(), d->m_selectedRegion.width()); d->updatePixmap(); // qApp->sendPostedEvents(0,QEvent::LayoutRequest); // updatePixmap(); } break; case (Rotate270): { int x = d->m_selectedRegion.y(); int y = w - d->m_selectedRegion.x() - d->m_selectedRegion.width(); d->m_selectedRegion.setRect(x, y, d->m_selectedRegion.height(), d->m_selectedRegion.width()); d->updatePixmap(); // qApp->sendPostedEvents(0,QEvent::LayoutRequest); // updatePixmap(); } break; default: resetSelection(); } } emit pixmapRotated(); } void KPixmapRegionSelectorWidget::rotateClockwise() { rotate(Rotate90); } void KPixmapRegionSelectorWidget::rotateCounterclockwise() { rotate(Rotate270); } bool KPixmapRegionSelectorWidget::eventFilter(QObject *obj, QEvent *ev) { if (ev->type() == QEvent::MouseButtonPress) { QMouseEvent *mev = (QMouseEvent *)(ev); //qCDebug(KWidgetsAddonsLog) << QString("click at %1,%2").arg( mev->x() ).arg( mev->y() ); if (mev->button() == Qt::RightButton) { QMenu *popup = createPopupMenu(); popup->exec(mev->globalPos()); delete popup; return true; } QCursor cursor; if (d->m_selectedRegion.contains(mev->pos()) && d->m_selectedRegion != d->m_originalPixmap.rect()) { d->m_state = Private::Moving; cursor.setShape(Qt::SizeAllCursor); d->m_rubberBand->show(); } else { d->m_state = Private::Resizing; cursor.setShape(Qt::CrossCursor); } QApplication::setOverrideCursor(cursor); d->m_tempFirstClick = mev->pos(); return true; } if (ev->type() == QEvent::MouseMove) { QMouseEvent *mev = (QMouseEvent *)(ev); //qCDebug(KWidgetsAddonsLog) << QString("move to %1,%2").arg( mev->x() ).arg( mev->y() ); if (d->m_state == Private::Resizing) { setSelectedRegion( d->calcSelectionRectangle(d->m_tempFirstClick, mev->pos())); } else if (d->m_state == Private::Moving) { int mevx = mev->x(); int mevy = mev->y(); bool mouseOutside = false; if (mevx < 0) { d->m_selectedRegion.translate(-d->m_selectedRegion.x(), 0); mouseOutside = true; } else if (mevx > d->m_originalPixmap.width()) { d->m_selectedRegion.translate(d->m_originalPixmap.width() - d->m_selectedRegion.width() - d->m_selectedRegion.x(), 0); mouseOutside = true; } if (mevy < 0) { d->m_selectedRegion.translate(0, -d->m_selectedRegion.y()); mouseOutside = true; } else if (mevy > d->m_originalPixmap.height()) { d->m_selectedRegion.translate(0, d->m_originalPixmap.height() - d->m_selectedRegion.height() - d->m_selectedRegion.y()); mouseOutside = true; } if (mouseOutside) { d->updatePixmap(); return true; }; d->m_selectedRegion.translate(mev->x() - d->m_tempFirstClick.x(), mev->y() - d->m_tempFirstClick.y()); // Check that the region has not fallen outside the image if (d->m_selectedRegion.x() < 0) { d->m_selectedRegion.translate(-d->m_selectedRegion.x(), 0); } else if (d->m_selectedRegion.right() > d->m_originalPixmap.width()) { d->m_selectedRegion.translate(-(d->m_selectedRegion.right() - d->m_originalPixmap.width()), 0); } if (d->m_selectedRegion.y() < 0) { d->m_selectedRegion.translate(0, -d->m_selectedRegion.y()); } else if (d->m_selectedRegion.bottom() > d->m_originalPixmap.height()) { d->m_selectedRegion.translate(0, -(d->m_selectedRegion.bottom() - d->m_originalPixmap.height())); } d->m_tempFirstClick = mev->pos(); d->updatePixmap(); } return true; } if (ev->type() == QEvent::MouseButtonRelease) { QMouseEvent *mev = (QMouseEvent *)(ev); if (d->m_state == Private::Resizing && mev->pos() == d->m_tempFirstClick) { resetSelection(); } d->m_state = Private::None; QApplication::restoreOverrideCursor(); d->m_rubberBand->hide(); return true; } QWidget::eventFilter(obj, ev); return false; } QRect KPixmapRegionSelectorWidget::Private::calcSelectionRectangle(const QPoint &startPoint, const QPoint &_endPoint) { QPoint endPoint = _endPoint; if (endPoint.x() < 0) { endPoint.setX(0); } else if (endPoint.x() > m_originalPixmap.width()) { endPoint.setX(m_originalPixmap.width()); } if (endPoint.y() < 0) { endPoint.setY(0); } else if (endPoint.y() > m_originalPixmap.height()) { endPoint.setY(m_originalPixmap.height()); } int w = abs(startPoint.x() - endPoint.x()); int h = abs(startPoint.y() - endPoint.y()); if (m_forcedAspectRatio > 0) { double aspectRatio = w / double(h); if (aspectRatio > m_forcedAspectRatio) { h = (int)(w / m_forcedAspectRatio); } else { w = (int)(h * m_forcedAspectRatio); } } int x, y; if (startPoint.x() < endPoint.x()) { x = startPoint.x(); } else { x = startPoint.x() - w; } if (startPoint.y() < endPoint.y()) { y = startPoint.y(); } else { y = startPoint.y() - h; } if (x < 0) { w += x; x = 0; h = (int)(w / m_forcedAspectRatio); if (startPoint.y() > endPoint.y()) { y = startPoint.y() - h; } } else if (x + w > m_originalPixmap.width()) { w = m_originalPixmap.width() - x; h = (int)(w / m_forcedAspectRatio); if (startPoint.y() > endPoint.y()) { y = startPoint.y() - h; } } if (y < 0) { h += y; y = 0; w = (int)(h * m_forcedAspectRatio); if (startPoint.x() > endPoint.x()) { x = startPoint.x() - w; } } else if (y + h > m_originalPixmap.height()) { h = m_originalPixmap.height() - y; w = (int)(h * m_forcedAspectRatio); if (startPoint.x() > endPoint.x()) { x = startPoint.x() - w; } } return QRect(x, y, w, h); } QRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const { return QRect((int)(d->m_selectedRegion.x() / d->m_zoomFactor), (int)(d->m_selectedRegion.y() / d->m_zoomFactor), (int)(d->m_selectedRegion.width() / d->m_zoomFactor), (int)(d->m_selectedRegion.height() / d->m_zoomFactor)); } QImage KPixmapRegionSelectorWidget::selectedImage() const { QImage origImage = d->m_unzoomedPixmap.toImage(); return origImage.copy(unzoomedSelectedRegion()); } void KPixmapRegionSelectorWidget::setSelectionAspectRatio(int width, int height) { d->m_forcedAspectRatio = width / double(height); } void KPixmapRegionSelectorWidget::setFreeSelectionAspectRatio() { d->m_forcedAspectRatio = 0; } void KPixmapRegionSelectorWidget::setMaximumWidgetSize(int width, int height) { d->m_maxWidth = width; d->m_maxHeight = height; if (d->m_selectedRegion == d->m_originalPixmap.rect()) { d->m_selectedRegion = QRect(); } d->m_originalPixmap = d->m_unzoomedPixmap; // qCDebug(KWidgetsAddonsLog) << QString(" original Pixmap :") << d->m_originalPixmap.rect(); // qCDebug(KWidgetsAddonsLog) << QString(" unzoomed Pixmap : %1 x %2 ").arg(d->m_unzoomedPixmap.width()).arg(d->m_unzoomedPixmap.height()); if (!d->m_originalPixmap.isNull() && (d->m_originalPixmap.width() > d->m_maxWidth || d->m_originalPixmap.height() > d->m_maxHeight)) { /* We have to resize the pixmap to get it complete on the screen */ QImage image = d->m_originalPixmap.toImage(); d->m_originalPixmap = QPixmap::fromImage(image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation)); double oldZoomFactor = d->m_zoomFactor; d->m_zoomFactor = d->m_originalPixmap.width() / (double)d->m_unzoomedPixmap.width(); if (d->m_selectedRegion.isValid()) { d->m_selectedRegion = QRect((int)(d->m_selectedRegion.x() * d->m_zoomFactor / oldZoomFactor), (int)(d->m_selectedRegion.y() * d->m_zoomFactor / oldZoomFactor), (int)(d->m_selectedRegion.width() * d->m_zoomFactor / oldZoomFactor), (int)(d->m_selectedRegion.height() * d->m_zoomFactor / oldZoomFactor)); } } if (!d->m_selectedRegion.isValid()) { d->m_selectedRegion = d->m_originalPixmap.rect(); } d->m_linedPixmap = QPixmap(); d->updatePixmap(); resize(d->m_label->width(), d->m_label->height()); } diff --git a/src/kpixmapsequence.cpp b/src/kpixmapsequence.cpp index 5436226..78a8cce 100644 --- a/src/kpixmapsequence.cpp +++ b/src/kpixmapsequence.cpp @@ -1,131 +1,129 @@ /* Copyright 2008 Aurélien Gâteau Copyright 2009 Sebastian Trueg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kpixmapsequence.h" #include "loggingcategory.h" #include -#include #include -#include class Q_DECL_HIDDEN KPixmapSequence::Private : public QSharedData { public: QVector mFrames; void loadSequence(const QPixmap &bigPixmap, const QSize &frameSize); }; void KPixmapSequence::Private::loadSequence(const QPixmap &bigPixmap, const QSize &frameSize) { if (bigPixmap.isNull()) { qCWarning(KWidgetsAddonsLog) << "Invalid pixmap specified."; return; } QSize size(frameSize); if (!size.isValid()) { size = QSize(bigPixmap.width(), bigPixmap.width()); } if (bigPixmap.width() % size.width() || bigPixmap.height() % size.height()) { qCWarning(KWidgetsAddonsLog) << "Invalid framesize."; return; } const int rowCount = bigPixmap.height() / size.height(); const int colCount = bigPixmap.width() / size.width(); mFrames.resize(rowCount * colCount); int pos = 0; for (int row = 0; row < rowCount; ++row) { for (int col = 0; col < colCount; ++col) { QPixmap pix = bigPixmap.copy(col * size.width(), row * size.height(), size.width(), size.height()); mFrames[pos++] = pix; } } } KPixmapSequence::KPixmapSequence() : d(new Private) { } KPixmapSequence::KPixmapSequence(const KPixmapSequence &other) { d = other.d; } KPixmapSequence::KPixmapSequence(const QPixmap &bigPixmap, const QSize &frameSize) : d(new Private) { d->loadSequence(bigPixmap, frameSize); } KPixmapSequence::KPixmapSequence(const QString &fullPath, int size) : d(new Private) { d->loadSequence(QPixmap(fullPath), QSize(size, size)); } KPixmapSequence::~KPixmapSequence() { } KPixmapSequence &KPixmapSequence::operator=(const KPixmapSequence &other) { d = other.d; return *this; } bool KPixmapSequence::isValid() const { return !isEmpty(); } bool KPixmapSequence::isEmpty() const { return d->mFrames.isEmpty(); } QSize KPixmapSequence::frameSize() const { if (isEmpty()) { qCWarning(KWidgetsAddonsLog) << "No frame loaded"; return QSize(); } return d->mFrames[0].size(); } int KPixmapSequence::frameCount() const { return d->mFrames.size(); } QPixmap KPixmapSequence::frameAt(int index) const { if (isEmpty() || index > frameCount()-1 ) { qCWarning(KWidgetsAddonsLog) << "No frame loaded"; return QPixmap(); } return d->mFrames.at(index); } diff --git a/src/kratingpainter.cpp b/src/kratingpainter.cpp index e6aad30..471f562 100644 --- a/src/kratingpainter.cpp +++ b/src/kratingpainter.cpp @@ -1,381 +1,380 @@ /* This file is part of the KDE libraries Copyright (C) 2007-2008 Sebastian Trueg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kratingpainter.h" -#include #include #include #include #include #include class Q_DECL_HIDDEN KRatingPainter::Private { public: Private() : maxRating(10), spacing(0), isEnabled(true), bHalfSteps(true), alignment(Qt::AlignCenter), direction(Qt::LeftToRight) { } QPixmap getPixmap(int size, QIcon::State state = QIcon::On); int maxRating; int spacing; QIcon icon; bool isEnabled; bool bHalfSteps; Qt::Alignment alignment; Qt::LayoutDirection direction; QPixmap customPixmap; }; static void _k_imageToGrayScale(QImage &img, float value); QPixmap KRatingPainter::Private::getPixmap(int size, QIcon::State state) { bool toGray = (state == QIcon::Off); QPixmap p; if (!customPixmap.isNull()) { p = customPixmap.scaled(QSize(size, size)); } else { QIcon _icon(icon); if (_icon.isNull()) { if (state == QIcon::Off && QIcon::hasThemeIcon(QStringLiteral("rating-unrated"))) { _icon = QIcon::fromTheme(QStringLiteral("rating-unrated")); // our theme provided a separate icon, no need to desaturate toGray = false; } else { _icon = QIcon::fromTheme(QStringLiteral("rating")); } } p = _icon.pixmap(size); } if (toGray) { QImage img = p.toImage().convertToFormat(QImage::Format_ARGB32); _k_imageToGrayScale(img, 1.0); return QPixmap::fromImage(img); } return p; } KRatingPainter::KRatingPainter() : d(new Private()) { } KRatingPainter::~KRatingPainter() { delete d; } int KRatingPainter::maxRating() const { return d->maxRating; } bool KRatingPainter::halfStepsEnabled() const { return d->bHalfSteps; } Qt::Alignment KRatingPainter::alignment() const { return d->alignment; } Qt::LayoutDirection KRatingPainter::layoutDirection() const { return d->direction; } QIcon KRatingPainter::icon() const { return d->icon; } bool KRatingPainter::isEnabled() const { return d->isEnabled; } QPixmap KRatingPainter::customPixmap() const { return d->customPixmap; } int KRatingPainter::spacing() const { return d->spacing; } void KRatingPainter::setMaxRating(int max) { d->maxRating = max; } void KRatingPainter::setHalfStepsEnabled(bool enabled) { d->bHalfSteps = enabled; } void KRatingPainter::setAlignment(Qt::Alignment align) { d->alignment = align; } void KRatingPainter::setLayoutDirection(Qt::LayoutDirection direction) { d->direction = direction; } void KRatingPainter::setIcon(const QIcon &icon) { d->icon = icon; } void KRatingPainter::setEnabled(bool enabled) { d->isEnabled = enabled; } void KRatingPainter::setCustomPixmap(const QPixmap &pixmap) { d->customPixmap = pixmap; } void KRatingPainter::setSpacing(int s) { d->spacing = qMax(0, s); } static void _k_imageToGrayScale(QImage &img, float value) { QRgb *data = (QRgb *) img.bits(); QRgb *end = data + img.width() * img.height(); unsigned char gray; unsigned char val = (unsigned char)(255.0 * value); while (data != end) { gray = qGray(*data); *data = qRgba((val * gray + (255 - val) * qRed(*data)) >> 8, (val * gray + (255 - val) * qGreen(*data)) >> 8, (val * gray + (255 - val) * qBlue(*data)) >> 8, qAlpha(*data)); ++data; } } static void _k_imageToSemiTransparent(QImage &img) { QRgb *data = (QRgb *) img.bits(); QRgb *end = data + img.width() * img.height(); while (data != end) { *data = qRgba(qRed(*data), qGreen(*data), qBlue(*data), qAlpha(*data) >> 1); ++data; } } void KRatingPainter::paint(QPainter *painter, const QRect &rect, int rating, int hoverRating) const { rating = qMin(rating, d->maxRating); hoverRating = qMin(hoverRating, d->maxRating); int numUsedStars = d->bHalfSteps ? d->maxRating / 2 : d->maxRating; if (hoverRating >= 0 && hoverRating < rating) { int tmp = hoverRating; hoverRating = rating; rating = tmp; } int usedSpacing = d->spacing; // get the rating pixmaps int maxHSizeOnePix = (rect.width() - (numUsedStars - 1) * usedSpacing) / numUsedStars; QPixmap ratingPix = d->getPixmap(qMin(rect.height(), maxHSizeOnePix), QIcon::On); QSize ratingPixSize = ratingPix.size() / ratingPix.devicePixelRatio(); QPixmap disabledRatingPix = d->getPixmap(qMin(rect.height(), maxHSizeOnePix), QIcon::Off); QImage disabledRatingImage = disabledRatingPix.toImage().convertToFormat(QImage::Format_ARGB32); QPixmap hoverPix; // if we are disabled we become gray and more transparent if (!d->isEnabled) { ratingPix = disabledRatingPix; _k_imageToSemiTransparent(disabledRatingImage); disabledRatingPix = QPixmap::fromImage(disabledRatingImage); } bool half = d->bHalfSteps && rating % 2; int numRatingStars = d->bHalfSteps ? rating / 2 : rating; int numHoverStars = 0; bool halfHover = false; if (hoverRating >= 0 && rating != hoverRating && d->isEnabled) { numHoverStars = d->bHalfSteps ? hoverRating / 2 : hoverRating; halfHover = d->bHalfSteps && hoverRating % 2; disabledRatingImage = ratingPix.toImage().convertToFormat(QImage::Format_ARGB32); _k_imageToGrayScale(disabledRatingImage, 0.5); hoverPix = QPixmap::fromImage(disabledRatingImage); } if (d->alignment & Qt::AlignJustify && numUsedStars > 1) { int w = rect.width(); w -= numUsedStars * ratingPixSize.width(); usedSpacing = w / (numUsedStars - 1); } int ratingAreaWidth = ratingPixSize.width() * numUsedStars + usedSpacing * (numUsedStars - 1); int i = 0; int x = rect.x(); if (d->alignment & Qt::AlignRight) { x += (rect.width() - ratingAreaWidth); } else if (d->alignment & Qt::AlignHCenter) { x += (rect.width() - ratingAreaWidth) / 2; } int xInc = ratingPixSize.width() + usedSpacing; if (d->direction == Qt::RightToLeft) { x = rect.width() - ratingPixSize.width() - x; xInc = -xInc; } int y = rect.y(); if (d->alignment & Qt::AlignVCenter) { y += (rect.height() / 2 - ratingPixSize.height() / 2); } else if (d->alignment & Qt::AlignBottom) { y += (rect.height() - ratingPixSize.height()); } for (; i < numRatingStars; ++i) { painter->drawPixmap(x, y, ratingPix); x += xInc; } if (half) { painter->drawPixmap(x, y, ratingPixSize.width() / 2, ratingPixSize.height(), d->direction == Qt::RightToLeft ? (numHoverStars > 0 ? hoverPix : disabledRatingPix) : ratingPix, 0, 0, ratingPix.width() / 2, ratingPix.height()); //source sizes are deliberately not device independent painter->drawPixmap(x + ratingPixSize.width() / 2, y, ratingPixSize.width() / 2, ratingPixSize.height(), d->direction == Qt::RightToLeft ? ratingPix : (numHoverStars > 0 ? hoverPix : disabledRatingPix), ratingPix.width() / 2, 0, ratingPix.width() / 2, ratingPix.height()); x += xInc; ++i; } for (; i < numHoverStars; ++i) { painter->drawPixmap(x, y, hoverPix); x += xInc; } if (halfHover) { painter->drawPixmap(x, y, ratingPixSize.width() / 2, ratingPixSize.height(), d->direction == Qt::RightToLeft ? disabledRatingPix : hoverPix, 0, 0, ratingPix.width() / 2, ratingPix.height()); painter->drawPixmap(x + ratingPixSize.width() / 2, y, ratingPixSize.width() / 2, ratingPixSize.height(), d->direction == Qt::RightToLeft ? hoverPix : disabledRatingPix, ratingPix.width() / 2, 0, ratingPix.width() / 2, ratingPix.height()); x += xInc; ++i; } for (; i < numUsedStars; ++i) { painter->drawPixmap(x, y, disabledRatingPix); x += xInc; } } int KRatingPainter::ratingFromPosition(const QRect &rect, const QPoint &pos) const { int usedSpacing = d->spacing; int numUsedStars = d->bHalfSteps ? d->maxRating / 2 : d->maxRating; int maxHSizeOnePix = (rect.width() - (numUsedStars - 1) * usedSpacing) / numUsedStars; QPixmap ratingPix = d->getPixmap(qMin(rect.height(), maxHSizeOnePix)); QSize ratingPixSize = ratingPix.size() / ratingPix.devicePixelRatio(); int ratingAreaWidth = ratingPixSize.width() * numUsedStars + usedSpacing * (numUsedStars - 1); QRect usedRect(rect); if (d->alignment & Qt::AlignRight) { usedRect.setLeft(rect.right() - ratingAreaWidth); } else if (d->alignment & Qt::AlignHCenter) { int x = (rect.width() - ratingAreaWidth) / 2; usedRect.setLeft(rect.left() + x); usedRect.setRight(rect.right() - x); } else { // d->alignment & Qt::AlignLeft usedRect.setRight(rect.left() + ratingAreaWidth - 1); } if (d->alignment & Qt::AlignBottom) { usedRect.setTop(rect.bottom() - ratingPixSize.height() + 1); } else if (d->alignment & Qt::AlignVCenter) { int x = (rect.height() - ratingPixSize.height()) / 2; usedRect.setTop(rect.top() + x); usedRect.setBottom(rect.bottom() - x); } else { // d->alignment & Qt::AlignTop usedRect.setBottom(rect.top() + ratingPixSize.height() - 1); } if (usedRect.contains(pos)) { int x = 0; if (d->direction == Qt::RightToLeft) { x = usedRect.right() - pos.x(); } else { x = pos.x() - usedRect.left(); } double one = (double)usedRect.width() / (double)d->maxRating; // qCDebug(KWidgetsAddonsLog) << "rating:" << ( int )( ( double )x/one + 0.5 ); return (int)((double)x / one + 0.5); } else { return -1; } } void KRatingPainter::paintRating(QPainter *painter, const QRect &rect, Qt::Alignment align, int rating, int hoverRating) { KRatingPainter rp; rp.setAlignment(align); rp.setLayoutDirection(painter->layoutDirection()); rp.paint(painter, rect, rating, hoverRating); } int KRatingPainter::getRatingFromPosition(const QRect &rect, Qt::Alignment align, Qt::LayoutDirection direction, const QPoint &pos) { KRatingPainter rp; rp.setAlignment(align); rp.setLayoutDirection(direction); return rp.ratingFromPosition(rect, pos); } diff --git a/src/kratingwidget.cpp b/src/kratingwidget.cpp index 423e577..44023f9 100644 --- a/src/kratingwidget.cpp +++ b/src/kratingwidget.cpp @@ -1,267 +1,266 @@ /* * This file is part of the KDE libraries * Copyright (C) 2006-2007 Sebastian Trueg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kratingwidget.h" #include "kratingpainter.h" #include #include -#include -#include #include +#include class Q_DECL_HIDDEN KRatingWidget::Private { public: Private() : rating(0), hoverRating(-1), pixSize(16) { } int rating; int hoverRating; int pixSize; KRatingPainter ratingPainter; }; KRatingWidget::KRatingWidget(QWidget *parent) : QFrame(parent), d(new Private()) { setMouseTracking(true); } KRatingWidget::~KRatingWidget() { delete d; } #ifndef KWIDGETSADDONS_NO_DEPRECATED void KRatingWidget::setPixmap(const QPixmap &pix) { setCustomPixmap(pix); } #endif void KRatingWidget::setCustomPixmap(const QPixmap &pix) { d->ratingPainter.setCustomPixmap(pix); update(); } void KRatingWidget::setIcon(const QIcon &icon) { d->ratingPainter.setIcon(icon); update(); } void KRatingWidget::setPixmapSize(int size) { d->pixSize = size; updateGeometry(); } int KRatingWidget::spacing() const { return d->ratingPainter.spacing(); } QIcon KRatingWidget::icon() const { return d->ratingPainter.icon(); } void KRatingWidget::setSpacing(int s) { d->ratingPainter.setSpacing(s); update(); } Qt::Alignment KRatingWidget::alignment() const { return d->ratingPainter.alignment(); } void KRatingWidget::setAlignment(Qt::Alignment align) { d->ratingPainter.setAlignment(align); update(); } Qt::LayoutDirection KRatingWidget::layoutDirection() const { return d->ratingPainter.layoutDirection(); } void KRatingWidget::setLayoutDirection(Qt::LayoutDirection direction) { d->ratingPainter.setLayoutDirection(direction); update(); } unsigned int KRatingWidget::rating() const { return d->rating; } int KRatingWidget::maxRating() const { return d->ratingPainter.maxRating(); } bool KRatingWidget::halfStepsEnabled() const { return d->ratingPainter.halfStepsEnabled(); } #ifndef KWIDGETSADDONS_NO_DEPRECATED void KRatingWidget::setRating(unsigned int rating) { setRating((int)rating); } #endif void KRatingWidget::setRating(int rating) { if (rating != d->rating) { d->rating = rating; d->hoverRating = rating; emit ratingChanged(rating); emit ratingChanged((unsigned int)rating); update(); } } #ifndef KWIDGETSADDONS_NO_DEPRECATED void KRatingWidget::setMaxRating(unsigned int max) { setMaxRating((int)max); } #endif void KRatingWidget::setMaxRating(int max) { d->ratingPainter.setMaxRating(max); update(); } void KRatingWidget::setHalfStepsEnabled(bool enabled) { d->ratingPainter.setHalfStepsEnabled(enabled); update(); } #ifndef KWIDGETSADDONS_NO_DEPRECATED void KRatingWidget::setOnlyPaintFullSteps(bool fs) { setHalfStepsEnabled(!fs); } #endif static inline int adjustedHoverRating(bool halfStep, int hoverRating, int rating) { // intentionally skip zero, or half step is disabled. if (!halfStep || hoverRating == 0) { return hoverRating; } // See bug 171343, if we click on a star we want it to be full star, click again // make it half, click third time make it clear. // round up hoverRating to next full star rating const int hoveredFullStarRating = hoverRating + (hoverRating % 2); // Check if the star under mouse is the last half or whole star of the rating. if (hoveredFullStarRating == rating || hoveredFullStarRating == rating + 1) { // If current pointed star is not empty, next rating will be rating - 1 // if we point at 4th star and rating is 8 (4 star), next click will make it 7 // if we point at 4th star and rating is 7 (3.5 star), next click will make it 6 hoverRating = rating - 1; } else { // otherwise make it a full star rating hoverRating = hoveredFullStarRating; } return hoverRating; } void KRatingWidget::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { d->hoverRating = adjustedHoverRating(halfStepsEnabled(), d->ratingPainter.ratingFromPosition(contentsRect(), e->pos()), d->rating); // avoid set a rating to something less than zero, it may happen if widget is scaled and // mouse is clicked outside the star region. if (d->hoverRating >= 0) { setRating(d->hoverRating); } } } void KRatingWidget::mouseMoveEvent(QMouseEvent *e) { // when moving the mouse we show the user what the result of clicking will be const int prevHoverRating = d->hoverRating; d->hoverRating = adjustedHoverRating(halfStepsEnabled(), d->ratingPainter.ratingFromPosition(contentsRect(), e->pos()), d->rating); if (d->hoverRating != prevHoverRating) { update(); } } void KRatingWidget::leaveEvent(QEvent *) { d->hoverRating = -1; update(); } void KRatingWidget::paintEvent(QPaintEvent *e) { QFrame::paintEvent(e); QPainter p(this); d->ratingPainter.setEnabled(isEnabled()); d->ratingPainter.paint(&p, contentsRect(), d->rating, d->hoverRating); } QSize KRatingWidget::sizeHint() const { int numPix = d->ratingPainter.maxRating(); if (d->ratingPainter.halfStepsEnabled()) { numPix /= 2; } QSize pixSize(d->pixSize, d->pixSize); if (!d->ratingPainter.customPixmap().isNull()) { pixSize = d->ratingPainter.customPixmap().size() / d->ratingPainter.customPixmap().devicePixelRatio(); } return QSize(pixSize.width() * numPix + spacing() * (numPix - 1) + frameWidth() * 2, pixSize.height() + frameWidth() * 2); } void KRatingWidget::resizeEvent(QResizeEvent *e) { QFrame::resizeEvent(e); } #include "moc_kratingwidget.cpp" diff --git a/src/kselectaction.cpp b/src/kselectaction.cpp index 26cf7b2..8637c25 100644 --- a/src/kselectaction.cpp +++ b/src/kselectaction.cpp @@ -1,780 +1,779 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2002 Joseph Wenninger (C) 2003 Andras Mantia (C) 2005-2006 Hamish Rodda (C) 2006 Albert Astals Cid (C) 2006 Clarence Dang (C) 2006 Michel Hermier (C) 2007 Nick Shaforostoff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kselectaction.h" #include "kselectaction_p.h" #include "loggingcategory.h" #include -#include #include #include #include #include #include // QAction::setText("Hi") and then KPopupAccelManager exec'ing, causes // QAction::text() to return "&Hi" :( Comboboxes don't have accels and // display ampersands literally. static QString DropAmpersands(const QString &text) { QString label = text; int p = label.indexOf(QLatin1Char('&')); while (p >= 0 && p < label.length() - 1) { if (label[p + 1].isLetterOrNumber() // Valid accelerator. || label[p + 1] == QLatin1Char('&')) { // Escaped accelerator marker. label = label.left(p) + label.mid(p + 1); } p = label.indexOf(QLatin1Char('&'), p + 1); } return label; } KSelectAction::KSelectAction(QObject *parent) : QWidgetAction(parent) , d_ptr(new KSelectActionPrivate()) { Q_D(KSelectAction); d->init(this); } KSelectAction::KSelectAction(const QString &text, QObject *parent) : QWidgetAction(parent) , d_ptr(new KSelectActionPrivate()) { Q_D(KSelectAction); d->init(this); setText(text); } KSelectAction::KSelectAction(const QIcon &icon, const QString &text, QObject *parent) : QWidgetAction(parent) , d_ptr(new KSelectActionPrivate()) { Q_D(KSelectAction); setIcon(icon); setText(text); d->init(this); } KSelectAction::KSelectAction(KSelectActionPrivate &dd, QObject *parent) : QWidgetAction(parent) , d_ptr(&dd) { Q_D(KSelectAction); d->init(this); } KSelectAction::~KSelectAction() { menu()->deleteLater(); delete d_ptr; } void KSelectActionPrivate::init(KSelectAction *q) { q_ptr = q; QObject::connect(q_ptr->selectableActionGroup(), &QActionGroup::triggered, q_ptr, &KSelectAction::actionTriggered); QObject::connect(q_ptr, &QAction::toggled, q_ptr, &KSelectAction::slotToggled); q_ptr->setMenu(new QMenu()); q_ptr->setEnabled(false); } QActionGroup *KSelectAction::selectableActionGroup() const { Q_D(const KSelectAction); return d->m_actionGroup; } QList KSelectAction::actions() const { return selectableActionGroup()->actions(); } QAction *KSelectAction::currentAction() const { return selectableActionGroup()->checkedAction(); } int KSelectAction::currentItem() const { return selectableActionGroup()->actions().indexOf(currentAction()); } QString KSelectAction::currentText() const { if (QAction *a = currentAction()) { return ::DropAmpersands(a->text()); } return QString(); } bool KSelectAction::setCurrentAction(QAction *action) { //qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentAction(" << action << ")"; if (action) { if (actions().contains(action)) { if (action->isVisible() && action->isEnabled() && action->isCheckable()) { action->setChecked(true); if (isCheckable()) { setChecked(true); } return true; } else { qCWarning(KWidgetsAddonsLog) << "Action does not have the correct properties to be current:" << action->text(); } } else { qCWarning(KWidgetsAddonsLog) << "Action does not belong to group:" << action->text(); } return false; } if (currentAction()) { currentAction()->setChecked(false); } return false; } bool KSelectAction::setCurrentItem(int index) { //qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentIndex(" << index << ")"; return setCurrentAction(action(index)); } QAction *KSelectAction::action(int index) const { if (index >= 0 && index < selectableActionGroup()->actions().count()) { return selectableActionGroup()->actions().at(index); } return nullptr; } QAction *KSelectAction::action(const QString &text, Qt::CaseSensitivity cs) const { QString compare; if (cs == Qt::CaseSensitive) { compare = text; } else { compare = text.toLower(); } foreach (QAction *action, selectableActionGroup()->actions()) { const QString text = ::DropAmpersands(action->text()); if (cs == Qt::CaseSensitive) { if (text == compare) { return action; } } else if (cs == Qt::CaseInsensitive) { if (text.toLower() == compare) { return action; } } } return nullptr; } bool KSelectAction::setCurrentAction(const QString &text, Qt::CaseSensitivity cs) { //qCDebug(KWidgetsAddonsLog) << "KSelectAction::setCurrentAction(" << text << ",cs=" << cs << ")"; return setCurrentAction(action(text, cs)); } void KSelectAction::setComboWidth(int width) { Q_D(KSelectAction); if (width < 0) { return; } d->m_comboWidth = width; foreach (QComboBox *box, d->m_comboBoxes) { box->setMaximumWidth(d->m_comboWidth); } emit changed(); } void KSelectAction::setMaxComboViewCount(int n) { Q_D(KSelectAction); d->m_maxComboViewCount = n; foreach (QComboBox *box, d->m_comboBoxes) if (d->m_maxComboViewCount != -1) { box->setMaxVisibleItems(d->m_maxComboViewCount); } else // hardcoded qt default { box->setMaxVisibleItems(10); } emit changed(); } void KSelectAction::addAction(QAction *action) { insertAction(nullptr, action); } QAction *KSelectAction::addAction(const QString &text) { Q_D(KSelectAction); QAction *newAction = new QAction(parent()); newAction->setText(text); newAction->setCheckable(true); newAction->setProperty("isShortcutConfigurable", false); if (!d->m_menuAccelsEnabled) { newAction->setText(text); newAction->setShortcut(QKeySequence()); } addAction(newAction); return newAction; } QAction *KSelectAction::addAction(const QIcon &icon, const QString &text) { QAction *newAction = addAction(text); newAction->setIcon(icon); return newAction; } QAction *KSelectAction::removeAction(QAction *action) { Q_D(KSelectAction); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::removeAction(" << action << ")"; //int index = selectableActionGroup()->actions().indexOf(action); //qCDebug(KWidgetsAddonsLog) << "\tindex=" << index; // Removes the action from the group and sets its parent to null. d->m_actionGroup->removeAction(action); // Disable when no action is in the group bool hasActions = selectableActionGroup()->actions().isEmpty(); setEnabled(!hasActions); foreach (QToolButton *button, d->m_buttons) { button->setEnabled(!hasActions); button->removeAction(action); } foreach (QComboBox *comboBox, d->m_comboBoxes) { comboBox->setEnabled(!hasActions); comboBox->removeAction(action); } menu()->removeAction(action); return action; } void KSelectAction::insertAction(QAction *before, QAction *action) { Q_D(KSelectAction); action->setActionGroup(selectableActionGroup()); // Re-Enable when an action is added setEnabled(true); // Keep in sync with createToolBarWidget() foreach (QToolButton *button, d->m_buttons) { button->setEnabled(true); button->insertAction(before, action); } foreach (QComboBox *comboBox, d->m_comboBoxes) { comboBox->setEnabled(true); comboBox->insertAction(before, action); } menu()->insertAction(before, action); } void KSelectAction::actionTriggered(QAction *action) { // cache values so we don't need access to members in the action // after we've done an emit() const QString text = ::DropAmpersands(action->text()); const int index = selectableActionGroup()->actions().indexOf(action); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::actionTriggered(" << action << ") text=" << text // << " index=" << index << " emitting triggered()" << endl; if (isCheckable()) { // if this is subsidiary of other KSelectAction-derived class trigger(); // then imitate usual QAction behaviour so that other submenus (and their items) become unchecked } emit triggered(action); emit triggered(index); emit triggered(text); } QStringList KSelectAction::items() const { Q_D(const KSelectAction); QStringList ret; foreach (QAction *action, d->m_actionGroup->actions()) { ret << ::DropAmpersands(action->text()); } return ret; } void KSelectAction::changeItem(int index, const QString &text) { Q_D(KSelectAction); if (index < 0 || index >= actions().count()) { qCWarning(KWidgetsAddonsLog) << "KSelectAction::changeItem Index out of scope"; return; } actions()[index]->setText(d->makeMenuText(text)); } void KSelectAction::setItems(const QStringList &lst) { Q_D(KSelectAction); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::setItems(" << lst << ")"; clear(); foreach (const QString &string, lst) { if (!string.isEmpty()) { addAction(string); } else { QAction *action = new QAction(this); action->setSeparator(true); addAction(action); } } // Disable if empty and not editable setEnabled(lst.count() > 0 || d->m_edit); } int KSelectAction::comboWidth() const { Q_D(const KSelectAction); return d->m_comboWidth; } void KSelectAction::clear() { Q_D(KSelectAction); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::clear()"; // we need to delete the actions later since we may get a call to clear() // from a method called due to a triggered(...) signal const QList actions = d->m_actionGroup->actions(); for (int i = 0; i < actions.count(); ++i) { // deleteLater() only removes us from the actions() list (among // other things) on the next entry into the event loop. Until then, // e.g. action() and setCurrentItem() will be working on items // that are supposed to have been deleted. So detach the action to // prevent this from happening. removeAction(actions[i]); actions[i]->deleteLater(); } } void KSelectAction::removeAllActions() { Q_D(KSelectAction); while (d->m_actionGroup->actions().count()) { removeAction(d->m_actionGroup->actions().first()); } } void KSelectAction::setEditable(bool edit) { Q_D(KSelectAction); d->m_edit = edit; foreach (QComboBox *comboBox, d->m_comboBoxes) { comboBox->setEditable(edit); } emit changed(); } bool KSelectAction::isEditable() const { Q_D(const KSelectAction); return d->m_edit; } void KSelectAction::slotToggled(bool checked) { //if (checked && selectableActionGroup()->checkedAction()) if (!checked && currentAction()) { // other's submenu item has been selected currentAction()->setChecked(false); } } KSelectAction::ToolBarMode KSelectAction::toolBarMode() const { Q_D(const KSelectAction); return d->m_toolBarMode; } void KSelectAction::setToolBarMode(ToolBarMode mode) { Q_D(KSelectAction); d->m_toolBarMode = mode; } QToolButton::ToolButtonPopupMode KSelectAction::toolButtonPopupMode() const { Q_D(const KSelectAction); return d->m_toolButtonPopupMode; } void KSelectAction::setToolButtonPopupMode(QToolButton::ToolButtonPopupMode mode) { Q_D(KSelectAction); d->m_toolButtonPopupMode = mode; } void KSelectActionPrivate::_k_comboBoxDeleted(QObject *object) { foreach (QComboBox *comboBox, m_comboBoxes) if (object == comboBox) { m_comboBoxes.removeAll(static_cast(object)); break; } } void KSelectActionPrivate::_k_comboBoxCurrentIndexChanged(int index) { Q_Q(KSelectAction); //qCDebug(KWidgetsAddonsLog) << "KSelectActionPrivate::_k_comboBoxCurrentIndexChanged(" << index << ")"; QComboBox *triggeringCombo = qobject_cast (q->sender()); QAction *a = q->action(index); //qCDebug(KWidgetsAddonsLog) << "\ta=" << a; if (a) { //qCDebug(KWidgetsAddonsLog) << "\t\tsetting as current action"; a->trigger(); } else if (q->isEditable() && triggeringCombo && triggeringCombo->count() > 0 && index == triggeringCombo->count() - 1) { // User must have added a new item by typing and pressing enter. const QString newItemText = triggeringCombo->currentText(); //qCDebug(KWidgetsAddonsLog) << "\t\tuser typed new item '" << newItemText << "'"; // Only 1 combobox contains this and it's not a proper action. bool blocked = triggeringCombo->blockSignals(true); triggeringCombo->removeItem(index); triggeringCombo->blockSignals(blocked); QAction *newAction = q->addAction(newItemText); newAction->trigger(); } else { if (q->selectableActionGroup()->checkedAction()) { q->selectableActionGroup()->checkedAction()->setChecked(false); } } } // TODO: DropAmpersands() certainly makes sure this doesn't work. But I don't // think it did anyway esp. in the presence KCheckAccelerator - Clarence. void KSelectAction::setMenuAccelsEnabled(bool b) { Q_D(KSelectAction); d->m_menuAccelsEnabled = b; } bool KSelectAction::menuAccelsEnabled() const { Q_D(const KSelectAction); return d->m_menuAccelsEnabled; } QWidget *KSelectAction::createWidget(QWidget *parent) { Q_D(KSelectAction); QMenu *menu = qobject_cast(parent); if (menu) { // If used in a menu want to return 0 and use only the text, not a widget return nullptr; } ToolBarMode mode = toolBarMode(); QToolBar *toolBar = qobject_cast(parent); if (!toolBar && mode != ComboBoxMode) { // we can return a combobox just fine. return nullptr; } switch (mode) { case MenuMode: { QToolButton *button = new QToolButton(toolBar); button->setToolTip(toolTip()); button->setWhatsThis(whatsThis()); button->setStatusTip(statusTip()); button->setAutoRaise(true); button->setFocusPolicy(Qt::NoFocus); button->setIconSize(toolBar->iconSize()); button->setToolButtonStyle(toolBar->toolButtonStyle()); QObject::connect(toolBar, &QToolBar::iconSizeChanged, button, &QAbstractButton::setIconSize); QObject::connect(toolBar, &QToolBar::toolButtonStyleChanged, button, &QToolButton::setToolButtonStyle); button->setDefaultAction(this); QObject::connect(button, &QToolButton::triggered, toolBar, &QToolBar::actionTriggered); button->setPopupMode(toolButtonPopupMode()); button->addActions(selectableActionGroup()->actions()); d->m_buttons.append(button); return button; } case ComboBoxMode: { QComboBox *comboBox = new QComboBox(parent); comboBox->installEventFilter(this); if (d->m_maxComboViewCount != -1) { comboBox->setMaxVisibleItems(d->m_maxComboViewCount); } if (d->m_comboWidth > 0) { comboBox->setMaximumWidth(d->m_comboWidth); } comboBox->setEditable(isEditable()); comboBox->setToolTip(toolTip()); comboBox->setWhatsThis(whatsThis()); comboBox->setStatusTip(statusTip()); foreach (QAction *action, selectableActionGroup()->actions()) { comboBox->addAction(action); } if (selectableActionGroup()->actions().isEmpty()) { comboBox->setEnabled(false); } connect(comboBox, SIGNAL(destroyed(QObject*)), SLOT(_k_comboBoxDeleted(QObject*))); connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(_k_comboBoxCurrentIndexChanged(int))); d->m_comboBoxes.append(comboBox); return comboBox; } } return nullptr; } void KSelectAction::deleteWidget(QWidget *widget) { Q_D(KSelectAction); if (QToolButton *toolButton = qobject_cast(widget)) { d->m_buttons.removeAll(toolButton); } else if (QComboBox *comboBox = qobject_cast(widget)) { d->m_comboBoxes.removeAll(comboBox); } QWidgetAction::deleteWidget(widget); } bool KSelectAction::event(QEvent *event) { Q_D(KSelectAction); if (event->type() == QEvent::ActionChanged) { Q_FOREACH (QComboBox *comboBox, d->m_comboBoxes) { comboBox->setToolTip(toolTip()); comboBox->setWhatsThis(whatsThis()); comboBox->setStatusTip(statusTip()); } Q_FOREACH (QToolButton *toolButton, d->m_buttons) { toolButton->setToolTip(toolTip()); toolButton->setWhatsThis(whatsThis()); toolButton->setStatusTip(statusTip()); } } return QWidgetAction::event(event); } // KSelectAction::eventFilter() is called before action->setChecked() // invokes the signal to update QActionGroup so KSelectAction::currentItem() // returns an old value. There are 3 possibilities, where n actions will // report QAction::isChecked() where n is: // // 0: the checked action was unchecked // 1: the checked action did not change // 2: another action was checked but QActionGroup has not been invoked yet // to uncheck the one that was checked before // // TODO: we might want to cache this since QEvent::ActionChanged is fired // often. static int TrueCurrentItem(KSelectAction *sa) { QAction *curAction = sa->currentAction(); //qCDebug(KWidgetsAddonsLog) << "\tTrueCurrentItem(" << sa << ") curAction=" << curAction; foreach (QAction *action, sa->actions()) { if (action->isChecked()) { //qCDebug(KWidgetsAddonsLog) << "\t\taction " << action << " (text=" << action->text () << ") isChecked"; // 2 actions checked case? if (action != curAction) { //qCDebug(KWidgetsAddonsLog) << "\t\t\tmust be newly selected one"; return sa->actions().indexOf(action); } } } //qCDebug(KWidgetsAddonsLog) << "\t\tcurrent action still selected? " << (curAction && curAction->isChecked ()); // 1 or 0 actions checked case (in that order)? return (curAction && curAction->isChecked()) ? sa->actions().indexOf(curAction) : -1; } bool KSelectAction::eventFilter(QObject *watched, QEvent *event) { QComboBox *comboBox = qobject_cast (watched); if (!comboBox) { return false/*propagate event*/; } // If focus is lost, replace any edited text with the currently selected // item. if (event->type() == QEvent::FocusOut) { QFocusEvent *const e = static_cast (event); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(FocusOut)" // << " comboBox: ptr=" << comboBox // << " reason=" << e->reason () // << endl; if (e->reason() != Qt::ActiveWindowFocusReason/*switch window*/ && e->reason() != Qt::PopupFocusReason/*menu*/ && e->reason() != Qt::OtherFocusReason/*inconsistently reproduceable actions...*/) { //qCDebug(KWidgetsAddonsLog) << "\tkilling text"; comboBox->setEditText(comboBox->itemText(comboBox->currentIndex())); } return false/*propagate event*/; } bool blocked = comboBox->blockSignals(true); if (event->type() == QEvent::ActionAdded) { QActionEvent *const e = static_cast (event); const int index = e->before() ? comboBox->findData(QVariant::fromValue(e->before())) : comboBox->count(); const int newItem = ::TrueCurrentItem(this); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionAdded)" // << " comboBox: ptr=" << comboBox // << " currentItem=" << comboBox->currentIndex () // << " add index=" << index // << " action new: e->before=" << e->before () // << " ptr=" << e->action () // << " icon=" << e->action ()->icon () // << " text=" << e->action ()->text () // << " currentItem=" << newItem // << endl; comboBox->insertItem(index, e->action()->icon(), ::DropAmpersands(e->action()->text()), QVariant::fromValue(e->action())); if (QStandardItemModel *model = qobject_cast(comboBox->model())) { QStandardItem *item = model->item(index); item->setEnabled(e->action()->isEnabled()); } // Inserting an item into a combobox can change the current item so // make sure the item corresponding to the checked action is selected. comboBox->setCurrentIndex(newItem); } else if (event->type() == QEvent::ActionChanged) { QActionEvent *const e = static_cast (event); const int index = comboBox->findData(QVariant::fromValue(e->action())); const int newItem = ::TrueCurrentItem(this); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionChanged)" // << " comboBox: ptr=" << comboBox // << " currentItem=" << comboBox->currentIndex () // << " changed action's index=" << index // << " action new: ptr=" << e->action () // << " icon=" << e->action ()->icon () // << " text=" << e->action ()->text () // << " currentItem=" << newItem // << endl; comboBox->setItemIcon(index, e->action()->icon()); comboBox->setItemText(index, ::DropAmpersands(e->action()->text())); if (QStandardItemModel *model = qobject_cast(comboBox->model())) { QStandardItem *item = model->item(index); item->setEnabled(e->action()->isEnabled()); } // The checked action may have become unchecked so // make sure the item corresponding to the checked action is selected. comboBox->setCurrentIndex(newItem); } else if (event->type() == QEvent::ActionRemoved) { QActionEvent *const e = static_cast (event); const int index = comboBox->findData(QVariant::fromValue(e->action())); const int newItem = ::TrueCurrentItem(this); //qCDebug(KWidgetsAddonsLog) << "KSelectAction::eventFilter(ActionRemoved)" // << " comboBox: ptr=" << comboBox // << " currentItem=" << comboBox->currentIndex () // << " delete action index=" << index // << " new: currentItem=" << newItem // << endl; comboBox->removeItem(index); // Removing an item from a combobox can change the current item so // make sure the item corresponding to the checked action is selected. comboBox->setCurrentIndex(newItem); } comboBox->blockSignals(blocked); return false/*propagate event*/; } // END #include "moc_kselectaction.cpp" diff --git a/src/kselector.cpp b/src/kselector.cpp index c110a37..48731de 100644 --- a/src/kselector.cpp +++ b/src/kselector.cpp @@ -1,435 +1,434 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kselector.h" -#include #include #include #include #include #include //----------------------------------------------------------------------------- /* * 1D value selector with contents drawn by derived class. * See KColorDialog for example. */ #define ARROWSIZE 5 class Q_DECL_HIDDEN KSelector::Private { public: Private() { arrowPE = QStyle::PE_IndicatorArrowLeft; m_indent = true; } bool m_indent; QStyle::PrimitiveElement arrowPE; }; class Q_DECL_HIDDEN KGradientSelector::KGradientSelectorPrivate { public: KGradientSelectorPrivate(KGradientSelector *q): q(q) {} KGradientSelector *q; QLinearGradient gradient; QString text1; QString text2; }; KSelector::KSelector(QWidget *parent) : QAbstractSlider(parent) , d(new Private) { setOrientation(Qt::Horizontal); } KSelector::KSelector(Qt::Orientation o, QWidget *parent) : QAbstractSlider(parent) , d(new Private) { setOrientation(o); if (o == Qt::Horizontal) { setArrowDirection(Qt::UpArrow); } } KSelector::~KSelector() { delete d; } void KSelector::setIndent(bool i) { d->m_indent = i; } bool KSelector::indent() const { return d->m_indent; } QRect KSelector::contentsRect() const { int w = indent() ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0; //TODO: is the height:width ratio of an indicator arrow always 2:1? hm. int iw = (w < ARROWSIZE) ? ARROWSIZE : w; if (orientation() == Qt::Vertical) { if (arrowDirection() == Qt::RightArrow) { return QRect(w + ARROWSIZE, iw, width() - w * 2 - ARROWSIZE, height() - iw * 2); } else { return QRect(w, iw, width() - w * 2 - ARROWSIZE, height() - iw * 2); } } else { // Qt::Horizontal if (arrowDirection() == Qt::UpArrow) { return QRect(iw, w, width() - 2 * iw, height() - w * 2 - ARROWSIZE); } else { return QRect(iw, w + ARROWSIZE, width() - 2 * iw, height() - w * 2 - ARROWSIZE); } } } void KSelector::paintEvent(QPaintEvent *) { QPainter painter; int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); int iw = (w < ARROWSIZE) ? ARROWSIZE : w; painter.begin(this); drawContents(&painter); QPoint pos = calcArrowPos(value()); drawArrow(&painter, pos); if (indent()) { QStyleOptionFrame opt; opt.initFrom(this); opt.state = QStyle::State_Sunken; if (orientation() == Qt::Vertical) { opt.rect.adjust(0, iw - w, -5, w - iw); } else { opt.rect.adjust(iw - w, 0, w - iw, -5); } QBrush oldBrush = painter.brush(); painter.setBrush(Qt::NoBrush); style()->drawPrimitive(QStyle::PE_Frame, &opt, &painter, this); painter.setBrush(oldBrush); } painter.end(); } void KSelector::mousePressEvent(QMouseEvent *e) { setSliderDown(true); moveArrow(e->pos()); } void KSelector::mouseMoveEvent(QMouseEvent *e) { moveArrow(e->pos()); } void KSelector::mouseReleaseEvent(QMouseEvent *e) { moveArrow(e->pos()); setSliderDown(false); } void KSelector::wheelEvent(QWheelEvent *e) { int val = value() + e->delta() / 120; setSliderDown(true); setValue(val); setSliderDown(false); } void KSelector::moveArrow(const QPoint &pos) { int val; int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); int iw = (w < ARROWSIZE) ? ARROWSIZE : w; if (orientation() == Qt::Vertical) val = (maximum() - minimum()) * (height() - pos.y() - iw) / (height() - iw * 2) + minimum(); else val = (maximum() - minimum()) * (pos.x() - iw) / (width() - iw * 2) + minimum(); setValue(val); update(); } QPoint KSelector::calcArrowPos(int val) { QPoint p; int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); int iw = (w < ARROWSIZE) ? ARROWSIZE : w; if (orientation() == Qt::Vertical) { p.setY(height() - iw - 1 - (height() - 2 * iw - 1) * val / (maximum() - minimum())); if (d->arrowPE == QStyle::PE_IndicatorArrowRight) { p.setX(0); } else { p.setX(width() - 5); } } else { p.setX(iw + (width() - 2 * iw - 1) * val / (maximum() - minimum())); if (d->arrowPE == QStyle::PE_IndicatorArrowDown) { p.setY(0); } else { p.setY(height() - 5); } } return p; } void KSelector::setArrowDirection(Qt::ArrowType direction) { switch (direction) { case Qt::UpArrow: if (orientation() == Qt::Horizontal) { d->arrowPE = QStyle::PE_IndicatorArrowUp; } else { d->arrowPE = QStyle::PE_IndicatorArrowLeft; } break; case Qt::DownArrow: if (orientation() == Qt::Horizontal) { d->arrowPE = QStyle::PE_IndicatorArrowDown; } else { d->arrowPE = QStyle::PE_IndicatorArrowRight; } break; case Qt::LeftArrow: if (orientation() == Qt::Vertical) { d->arrowPE = QStyle::PE_IndicatorArrowLeft; } else { d->arrowPE = QStyle::PE_IndicatorArrowDown; } break; case Qt::RightArrow: if (orientation() == Qt::Vertical) { d->arrowPE = QStyle::PE_IndicatorArrowRight; } else { d->arrowPE = QStyle::PE_IndicatorArrowUp; } break; case Qt::NoArrow: break; } } Qt::ArrowType KSelector::arrowDirection() const { switch (d->arrowPE) { case QStyle::PE_IndicatorArrowUp: return Qt::UpArrow; case QStyle::PE_IndicatorArrowDown: return Qt::DownArrow; case QStyle::PE_IndicatorArrowRight: return Qt::RightArrow; case QStyle::PE_IndicatorArrowLeft: default: return Qt::LeftArrow; } } void KSelector::drawContents(QPainter *) {} void KSelector::drawArrow(QPainter *painter, const QPoint &pos) { painter->setPen(QPen()); painter->setBrush(QBrush(palette().color(QPalette::ButtonText))); QStyleOption o; if (orientation() == Qt::Vertical) { o.rect = QRect(pos.x(), pos.y() - ARROWSIZE / 2, ARROWSIZE, ARROWSIZE); } else { o.rect = QRect(pos.x() - ARROWSIZE / 2, pos.y(), ARROWSIZE, ARROWSIZE); } style()->drawPrimitive(d->arrowPE, &o, painter, this); } //---------------------------------------------------------------------------- KGradientSelector::KGradientSelector(QWidget *parent) : KSelector(parent), d(new KGradientSelectorPrivate(this)) { } KGradientSelector::KGradientSelector(Qt::Orientation o, QWidget *parent) : KSelector(o, parent), d(new KGradientSelectorPrivate(this)) { } KGradientSelector::~KGradientSelector() { delete d; } void KGradientSelector::drawContents(QPainter *painter) { d->gradient.setStart(contentsRect().topLeft()); if (orientation() == Qt::Vertical) { d->gradient.setFinalStop(contentsRect().bottomLeft()); } else { d->gradient.setFinalStop(contentsRect().topRight()); } QBrush gradientBrush(d->gradient); if (!gradientBrush.isOpaque()) { QPixmap chessboardPattern(16, 16); QPainter patternPainter(&chessboardPattern); patternPainter.fillRect(0, 0, 8, 8, Qt::black); patternPainter.fillRect(8, 8, 8, 8, Qt::black); patternPainter.fillRect(0, 8, 8, 8, Qt::white); patternPainter.fillRect(8, 0, 8, 8, Qt::white); patternPainter.end(); painter->fillRect(contentsRect(), QBrush(chessboardPattern)); } painter->fillRect(contentsRect(), gradientBrush); if (orientation() == Qt::Vertical) { int yPos = contentsRect().top() + painter->fontMetrics().ascent() + 2; int xPos = contentsRect().left() + (contentsRect().width() - painter->fontMetrics().width(d->text2)) / 2; QPen pen(qGray(firstColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(xPos, yPos, d->text2); yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; xPos = contentsRect().left() + (contentsRect().width() - painter->fontMetrics().width(d->text1)) / 2; pen.setColor(qGray(secondColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(xPos, yPos, d->text1); } else { int yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; QPen pen(qGray(firstColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(contentsRect().left() + 2, yPos, d->text1); pen.setColor(qGray(secondColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(contentsRect().right() - painter->fontMetrics().width(d->text2) - 2, yPos, d->text2); } } QSize KGradientSelector::minimumSize() const { return sizeHint(); } void KGradientSelector::setStops(const QGradientStops &stops) { d->gradient.setStops(stops); update(); } QGradientStops KGradientSelector::stops() const { return d->gradient.stops(); } void KGradientSelector::setColors(const QColor &col1, const QColor &col2) { d->gradient.setColorAt(0.0, col1); d->gradient.setColorAt(1.0, col2); update(); } void KGradientSelector::setText(const QString &t1, const QString &t2) { d->text1 = t1; d->text2 = t2; update(); } void KGradientSelector::setFirstColor(const QColor &col) { d->gradient.setColorAt(0.0, col); update(); } void KGradientSelector::setSecondColor(const QColor &col) { d->gradient.setColorAt(1.0, col); update(); } void KGradientSelector::setFirstText(const QString &t) { d->text1 = t; update(); } void KGradientSelector::setSecondText(const QString &t) { d->text2 = t; update(); } QColor KGradientSelector::firstColor() const { return d->gradient.stops().first().second; } QColor KGradientSelector::secondColor() const { return d->gradient.stops().last().second; } QString KGradientSelector::firstText() const { return d->text1; } QString KGradientSelector::secondText() const { return d->text2; } diff --git a/src/kseparator.cpp b/src/kseparator.cpp index 5177a20..f2cd24b 100644 --- a/src/kseparator.cpp +++ b/src/kseparator.cpp @@ -1,58 +1,56 @@ /* * Copyright (C) 1997 Michael Roth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "kseparator.h" #include -#include -#include KSeparator::KSeparator(QWidget *parent, Qt::WindowFlags f) : QFrame(parent, f) { setLineWidth(1); setMidLineWidth(0); setOrientation(Qt::Horizontal); } KSeparator::KSeparator(Qt::Orientation orientation, QWidget *parent, Qt::WindowFlags f) : QFrame(parent, f) { setLineWidth(1); setMidLineWidth(0); setOrientation(orientation); } void KSeparator::setOrientation(Qt::Orientation orientation) { if (orientation == Qt::Vertical) { setFrameShape(QFrame::VLine); setFrameShadow(QFrame::Sunken); setMinimumSize(2, 0); } else { setFrameShape(QFrame::HLine); setFrameShadow(QFrame::Sunken); setMinimumSize(0, 2); } updateGeometry(); } Qt::Orientation KSeparator::orientation() const { return ((frameStyle() & VLine) == VLine) ? Qt::Vertical : Qt::Horizontal; } diff --git a/src/ksplittercollapserbutton.cpp b/src/ksplittercollapserbutton.cpp index 88f028c..0441b86 100644 --- a/src/ksplittercollapserbutton.cpp +++ b/src/ksplittercollapserbutton.cpp @@ -1,361 +1,359 @@ /* Copyright (c) 2014 Montel Laurent based on code: Copyright 2009 Aurélien Gâteau Copyright 2009 Kåre Sårs This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "ksplittercollapserbutton.h" // Qt #include #include -#include #include #include #include #include -#include enum Direction { LeftToRight = 0, RightToLeft, TopToBottom, BottomToTop }; const static int TIMELINE_DURATION = 500; const static qreal MINIMUM_OPACITY = 0.3; static const struct { Qt::ArrowType arrowVisible; Qt::ArrowType notArrowVisible; } s_arrowDirection[] = { {Qt::LeftArrow, Qt::RightArrow}, {Qt::RightArrow, Qt::LeftArrow}, {Qt::UpArrow, Qt::DownArrow}, {Qt::DownArrow, Qt::UpArrow} }; class Q_DECL_HIDDEN KSplitterCollapserButton::Private { public: Private(KSplitterCollapserButton *qq); KSplitterCollapserButton *q; QSplitter *splitter; QWidget *childWidget; Direction direction; QTimeLine *opacityTimeLine; QList sizeAtCollapse; bool isVertical() const; bool isWidgetCollapsed() const; void updatePosition(); void updateArrow(); void widgetEventFilter(QEvent *event); void updateOpacity(); void startTimeLine(); }; KSplitterCollapserButton::Private::Private(KSplitterCollapserButton *qq) : q(qq), splitter(nullptr), childWidget(nullptr), opacityTimeLine(nullptr) { } bool KSplitterCollapserButton::Private::isVertical() const { return (splitter->orientation() == Qt::Vertical); } bool KSplitterCollapserButton::Private::isWidgetCollapsed() const { const QRect widgetRect = childWidget->geometry(); if ((widgetRect.height() == 0) || (widgetRect.width() == 0)) { return true; } else { return false; } } void KSplitterCollapserButton::Private::updatePosition() { int x = 0; int y = 0; const QRect widgetRect = childWidget->geometry(); const int handleWidth = splitter->handleWidth(); if (!isVertical()) { const int splitterWidth = splitter->width(); const int width = q->sizeHint().width(); // FIXME: Make this configurable y = 30; if (direction == LeftToRight) { if (!isWidgetCollapsed()) { x = widgetRect.right() + handleWidth; } else { x = 0; } } else { // RightToLeft if (!isWidgetCollapsed()) { x = widgetRect.left() - handleWidth - width; } else { x = splitterWidth - handleWidth - width; } } } else { x = 30; const int height = q->sizeHint().height(); const int splitterHeight = splitter->height(); if (direction == TopToBottom) { if (!isWidgetCollapsed()) { y = widgetRect.bottom() + handleWidth; } else { y = 0; } } else { // BottomToTop if (!isWidgetCollapsed()) { y = widgetRect.top() - handleWidth - height; } else { y = splitterHeight - handleWidth - height; } } } q->move(x, y); } void KSplitterCollapserButton::Private::updateArrow() { q->setArrowType(isWidgetCollapsed() ? s_arrowDirection[direction].notArrowVisible : s_arrowDirection[direction].arrowVisible); } void KSplitterCollapserButton::Private::widgetEventFilter(QEvent *event) { switch (event->type()) { case QEvent::Resize: case QEvent::Move: case QEvent::Show: case QEvent::Hide: updatePosition(); updateOpacity(); updateArrow(); break; default: break; } } void KSplitterCollapserButton::Private::updateOpacity() { const QPoint pos = q->parentWidget()->mapFromGlobal(QCursor::pos()); const QRect opaqueRect = q->geometry(); const bool opaqueCollapser = opaqueRect.contains(pos); if (opaqueCollapser) { opacityTimeLine->setDirection(QTimeLine::Forward); startTimeLine(); } else { opacityTimeLine->setDirection(QTimeLine::Backward); startTimeLine(); } } void KSplitterCollapserButton::Private::startTimeLine() { if (opacityTimeLine->state() == QTimeLine::Running) { opacityTimeLine->stop(); } opacityTimeLine->start(); } KSplitterCollapserButton::KSplitterCollapserButton(QWidget *childWidget, QSplitter *splitter) : QToolButton(), d(new Private(this)) { setObjectName(QStringLiteral("splittercollapser")); // We do not want our collapser to be added as a regular widget in the // splitter! setAttribute(Qt::WA_NoChildEventsForParent); d->opacityTimeLine = new QTimeLine(TIMELINE_DURATION, this); d->opacityTimeLine->setFrameRange(int(MINIMUM_OPACITY * 1000), 1000); connect(d->opacityTimeLine, &QTimeLine::valueChanged, this, QOverload<>::of(&QWidget::update)); d->childWidget = childWidget; d->childWidget->installEventFilter(this); d->splitter = splitter; setParent(d->splitter); switch (splitter->orientation()) { case Qt::Horizontal: if (splitter->indexOf(childWidget) < splitter->count() / 2) { d->direction = LeftToRight; } else { d->direction = RightToLeft; } break; case Qt::Vertical: if (splitter->indexOf(childWidget) < splitter->count() / 2) { d->direction = TopToBottom; } else { d->direction = BottomToTop; } break; } connect(this, &KSplitterCollapserButton::clicked, this, &KSplitterCollapserButton::slotClicked); } KSplitterCollapserButton::~KSplitterCollapserButton() { delete d; } bool KSplitterCollapserButton::isWidgetCollapsed() const { return d->isWidgetCollapsed(); } bool KSplitterCollapserButton::eventFilter(QObject *object, QEvent *event) { if (object == d->childWidget) { d->widgetEventFilter(event); } return QToolButton::eventFilter(object, event); } void KSplitterCollapserButton::enterEvent(QEvent *event) { Q_UNUSED(event) d->updateOpacity(); } void KSplitterCollapserButton::leaveEvent(QEvent *event) { Q_UNUSED(event) d->updateOpacity(); } void KSplitterCollapserButton::showEvent(QShowEvent *event) { Q_UNUSED(event) d->updateOpacity(); } QSize KSplitterCollapserButton::sizeHint() const { QStyleOption opt; opt.initFrom(this); const int extent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt); QSize sh(extent * 3 / 4, extent * 240 / 100); if (d->isVertical()) { sh.transpose(); } return sh.expandedTo(QApplication::globalStrut()); } void KSplitterCollapserButton::slotClicked() { QList sizes = d->splitter->sizes(); const int index = d->splitter->indexOf(d->childWidget); if (!d->isWidgetCollapsed()) { d->sizeAtCollapse = sizes; sizes[index] = 0; } else { if (!d->sizeAtCollapse.isEmpty()) { sizes = d->sizeAtCollapse; } else { if (d->isVertical()) { sizes[index] = d->childWidget->sizeHint().height(); } else { sizes[index] = d->childWidget->sizeHint().width(); } } } d->splitter->setSizes(sizes); d->opacityTimeLine->setDirection(QTimeLine::Backward); d->startTimeLine(); } void KSplitterCollapserButton::collapse() { if (!d->isWidgetCollapsed()) { slotClicked(); } // else do nothing } void KSplitterCollapserButton::restore() { if (d->isWidgetCollapsed()) { slotClicked(); } // else do nothing } void KSplitterCollapserButton::setCollapsed(bool collapse) { if (collapse == d->isWidgetCollapsed()) { slotClicked(); } // else do nothing } void KSplitterCollapserButton::paintEvent(QPaintEvent *) { QStylePainter painter(this); const qreal opacity = d->opacityTimeLine->currentFrame() / 1000.; painter.setOpacity(opacity); QStyleOptionToolButton opt; initStyleOption(&opt); if (d->isVertical()) { if (d->direction == TopToBottom) { opt.rect.setTop(-height()); } else { opt.rect.setHeight(height() * 2); } } else { if (d->direction == LeftToRight) { opt.rect.setLeft(-width()); } else { opt.rect.setWidth(width() * 2); } } painter.drawPrimitive(QStyle::PE_PanelButtonTool, opt); QStyleOptionToolButton opt2; initStyleOption(&opt2); painter.drawControl(QStyle::CE_ToolButtonLabel, opt2); } diff --git a/src/ksqueezedtextlabel.cpp b/src/ksqueezedtextlabel.cpp index b2e9b5a..deb87f2 100644 --- a/src/ksqueezedtextlabel.cpp +++ b/src/ksqueezedtextlabel.cpp @@ -1,260 +1,259 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Ronny Standtke This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ksqueezedtextlabel.h" #include #include #include #include #include #include -#include #include class KSqueezedTextLabelPrivate { public: void _k_copyFullText() { QApplication::clipboard()->setText(fullText); } QString fullText; Qt::TextElideMode elideMode; }; KSqueezedTextLabel::KSqueezedTextLabel(const QString &text, QWidget *parent) : QLabel(parent), d(new KSqueezedTextLabelPrivate) { setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); d->fullText = text; d->elideMode = Qt::ElideMiddle; squeezeTextToLabel(); } KSqueezedTextLabel::KSqueezedTextLabel(QWidget *parent) : QLabel(parent), d(new KSqueezedTextLabelPrivate) { setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); d->elideMode = Qt::ElideMiddle; } KSqueezedTextLabel::~KSqueezedTextLabel() { delete d; } void KSqueezedTextLabel::resizeEvent(QResizeEvent *) { squeezeTextToLabel(); } QSize KSqueezedTextLabel::minimumSizeHint() const { QSize sh = QLabel::minimumSizeHint(); sh.setWidth(-1); return sh; } QSize KSqueezedTextLabel::sizeHint() const { int maxWidth = QApplication::desktop()->screenGeometry(this).width() * 3 / 4; QFontMetrics fm(fontMetrics()); int textWidth = fm.width(d->fullText); if (textWidth > maxWidth) { textWidth = maxWidth; } const int chromeWidth = width() - contentsRect().width(); return QSize(textWidth + chromeWidth, QLabel::sizeHint().height()); } void KSqueezedTextLabel::setIndent(int indent) { QLabel::setIndent(indent); squeezeTextToLabel(); } void KSqueezedTextLabel::setMargin(int margin) { QLabel::setMargin(margin); squeezeTextToLabel(); } void KSqueezedTextLabel::setText(const QString &text) { d->fullText = text; squeezeTextToLabel(); } void KSqueezedTextLabel::clear() { d->fullText.clear(); QLabel::clear(); } void KSqueezedTextLabel::squeezeTextToLabel() { QFontMetrics fm(fontMetrics()); const int labelWidth = contentsRect().width(); QStringList squeezedLines; bool squeezed = false; Q_FOREACH (const QString &line, d->fullText.split(QLatin1Char('\n'))) { int lineWidth = fm.width(line); if (lineWidth > labelWidth) { squeezed = true; squeezedLines << fm.elidedText(line, d->elideMode, labelWidth); } else { squeezedLines << line; } } if (squeezed) { QLabel::setText(squeezedLines.join(QStringLiteral("\n"))); setToolTip(d->fullText); } else { QLabel::setText(d->fullText); setToolTip(QString()); } } QRect KSqueezedTextLabel::contentsRect() const { // calculation according to API docs for QLabel::indent const int margin = this->margin(); int indent = this->indent(); if (indent < 0) { if (frameWidth() == 0) { indent = 0; } else { indent = fontMetrics().width(QLatin1Char('x')) / 2 - margin; } } QRect result = QLabel::contentsRect(); if (indent > 0) { const int alignment = this->alignment(); if (alignment & Qt::AlignLeft) { result.setLeft(result.left() + indent); } if (alignment & Qt::AlignTop) { result.setTop(result.top() + indent); } if (alignment & Qt::AlignRight) { result.setRight(result.right() - indent); } if (alignment & Qt::AlignBottom) { result.setBottom(result.bottom() - indent); } } result.adjust(margin, margin, -margin, -margin); return result; } void KSqueezedTextLabel::setAlignment(Qt::Alignment alignment) { // save fullText and restore it QString tmpFull(d->fullText); QLabel::setAlignment(alignment); d->fullText = tmpFull; } Qt::TextElideMode KSqueezedTextLabel::textElideMode() const { return d->elideMode; } void KSqueezedTextLabel::setTextElideMode(Qt::TextElideMode mode) { d->elideMode = mode; squeezeTextToLabel(); } QString KSqueezedTextLabel::fullText() const { return d->fullText; } bool KSqueezedTextLabel::isSqueezed() const { return d->fullText != text(); } void KSqueezedTextLabel::contextMenuEvent(QContextMenuEvent *ev) { // We want to reimplement "Copy" to include the elided text. // But this means reimplementing the full popup menu, so no more // copy-link-address or copy-selection support anymore, since we // have no access to the QTextDocument. // Maybe we should have a boolean flag in KSqueezedTextLabel itself for // whether to show the "Copy Full Text" custom popup? // For now I chose to show it when the text is squeezed; when it's not, the // standard popup menu can do the job (select all, copy). if (isSqueezed()) { QMenu menu(this); QAction *act = new QAction(tr("&Copy Full Text"), &menu); connect(act, &QAction::triggered, this, [this]() { d->_k_copyFullText(); }); menu.addAction(act); ev->accept(); menu.exec(ev->globalPos()); } else { QLabel::contextMenuEvent(ev); } } void KSqueezedTextLabel::mouseReleaseEvent(QMouseEvent *ev) { if (QApplication::clipboard()->supportsSelection() && textInteractionFlags() != Qt::NoTextInteraction && ev->button() == Qt::LeftButton && !d->fullText.isEmpty() && hasSelectedText()) { // Expand "..." when selecting with the mouse QString txt = selectedText(); const QChar ellipsisChar(0x2026); // from qtextengine.cpp const int dotsPos = txt.indexOf(ellipsisChar); if (dotsPos > -1) { // Ex: abcde...yz, selecting de...y (selectionStart=3) // charsBeforeSelection = selectionStart = 2 (ab) // charsAfterSelection = 1 (z) // final selection length= 26 - 2 - 1 = 23 const int start = selectionStart(); int charsAfterSelection = text().length() - start - selectedText().length(); txt = d->fullText; // Strip markup tags if (textFormat() == Qt::RichText || (textFormat() == Qt::AutoText && Qt::mightBeRichText(txt))) { txt.remove(QRegExp(QStringLiteral("<[^>]*>"))); // account for stripped characters charsAfterSelection -= d->fullText.length() - txt.length(); } txt = txt.mid(selectionStart(), txt.length() - start - charsAfterSelection); } QApplication::clipboard()->setText(txt, QClipboard::Selection); } else { QLabel::mouseReleaseEvent(ev); } } #include "moc_ksqueezedtextlabel.cpp" diff --git a/src/ktooltipwidget.cpp b/src/ktooltipwidget.cpp index 197f8b2..bc63fb2 100644 --- a/src/ktooltipwidget.cpp +++ b/src/ktooltipwidget.cpp @@ -1,247 +1,246 @@ /* * This file is part of the KDE project * Copyright (C) 2008 Fredrik Höglund * Copyright (C) 2008 Konstantin Heil * Copyright (C) 2009 Peter Penz * Copyright (C) 2017 Elvis Angelaccio * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "ktooltipwidget.h" -#include #include #include #include #include #include #include #include class Q_DECL_HIDDEN KToolTipWidget::KToolTipWidgetPrivate { public: KToolTipWidgetPrivate(KToolTipWidget *parent) : q(parent), layout(nullptr), content(nullptr), contentParent(nullptr) {} void init(); void addWidget(QWidget *widget); void removeWidget(); void show(const QPoint &pos, QWindow *transientParent); void storeParent(); void restoreParent(); QPoint centerBelow(const QRect &rect, QScreen *screen) const; KToolTipWidget *q; QTimer hideTimer; QVBoxLayout *layout; QWidget *content; QWidget *contentParent; }; void KToolTipWidget::KToolTipWidgetPrivate::init() { layout = new QVBoxLayout(q); hideTimer.setSingleShot(true); hideTimer.setInterval(500); connect(&hideTimer, &QTimer::timeout, q, &QWidget::hide); q->setAttribute(Qt::WA_TranslucentBackground); q->setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint); } void KToolTipWidget::KToolTipWidgetPrivate::addWidget(QWidget *widget) { removeWidget(); content = widget; storeParent(); layout->addWidget(content); connect(content, &QWidget::destroyed, q, &QWidget::hide); } void KToolTipWidget::KToolTipWidgetPrivate::removeWidget() { layout->removeWidget(content); restoreParent(); } void KToolTipWidget::KToolTipWidgetPrivate::show(const QPoint &pos, QWindow *transientParent) { if (pos.isNull()) { return; } q->move(pos); q->createWinId(); q->windowHandle()->setProperty("ENABLE_BLUR_BEHIND_HINT", true); q->windowHandle()->setTransientParent(transientParent); q->show(); } void KToolTipWidget::KToolTipWidgetPrivate::storeParent() { if (!content) { return; } contentParent = qobject_cast(content->parent()); } void KToolTipWidget::KToolTipWidgetPrivate::restoreParent() { if (!content || !contentParent) { return; } content->setParent(contentParent); } QPoint KToolTipWidget::KToolTipWidgetPrivate::centerBelow(const QRect &rect, QScreen *screen) const { // It must be assured that: // - the content is fully visible // - the content is not drawn inside rect const QSize size = q->sizeHint(); const int margin = q->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth); const QRect screenGeometry = screen->geometry(); const bool hasRoomToLeft = (rect.left() - size.width() - margin >= screenGeometry.left()); const bool hasRoomToRight = (rect.right() + size.width() + margin <= screenGeometry.right()); const bool hasRoomAbove = (rect.top() - size.height() - margin >= screenGeometry.top()); const bool hasRoomBelow = (rect.bottom() + size.height() + margin <= screenGeometry.bottom()); if (!hasRoomAbove && !hasRoomBelow && !hasRoomToLeft && !hasRoomToRight) { return QPoint(); } int x = 0; int y = 0; if (hasRoomBelow || hasRoomAbove) { x = qMax(screenGeometry.left(), rect.center().x() - size.width() / 2); if (x + size.width() >= screenGeometry.right()) { x = screenGeometry.right() - size.width() + 1; } Q_ASSERT(x >= 0); if (hasRoomBelow) { y = rect.bottom() + margin; } else { y = rect.top() - size.height() - margin + 1; } } else { Q_ASSERT(hasRoomToLeft || hasRoomToRight); if (hasRoomToRight) { x = rect.right() + margin; } else { x = rect.left() - size.width() - margin + 1; } // Put the tooltip at the bottom of the screen. The x-coordinate has already // been adjusted, so that no overlapping with rect occurs. y = screenGeometry.bottom() - size.height() + 1; } return QPoint(x, y); } KToolTipWidget::KToolTipWidget(QWidget *parent) : QWidget(parent), d(new KToolTipWidgetPrivate(this)) { d->init(); } KToolTipWidget::~KToolTipWidget() { d->restoreParent(); } void KToolTipWidget::showAt(const QPoint &pos, QWidget *content, QWindow *transientParent) { d->addWidget(content); d->show(pos, transientParent); } void KToolTipWidget::showBelow(const QRect &rect, QWidget *content, QWindow *transientParent) { d->addWidget(content); const QSize marginSize{ 2 * content->style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin), 2 * content->style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin)}; content->setMaximumSize(transientParent->screen()->geometry().size() - marginSize); d->show(d->centerBelow(rect, transientParent->screen()), transientParent); } int KToolTipWidget::hideDelay() const { return d->hideTimer.interval(); } void KToolTipWidget::hideLater() { if (!isVisible()) { return; } if (hideDelay() > 0) { d->hideTimer.start(); } else { hide(); } } void KToolTipWidget::setHideDelay(int delay) { d->hideTimer.setInterval(delay); } void KToolTipWidget::enterEvent(QEvent *) { // Ignore hide delay and leave tooltip visible. if (hideDelay() > 0) { d->hideTimer.stop(); } else { hide(); } } void KToolTipWidget::hideEvent(QHideEvent *) { d->removeWidget(); // Give time to the content widget to get his own hide event. QTimer::singleShot(0, this, &KToolTipWidget::hidden); } void KToolTipWidget::leaveEvent(QEvent *) { // Don't bother starting the hide timer, we are done. hide(); } void KToolTipWidget::paintEvent(QPaintEvent *event) { QStylePainter painter(this); painter.setClipRegion(event->region()); QStyleOptionFrame option; option.init(this); painter.drawPrimitive(QStyle::PE_PanelTipLabel, option); painter.end(); QWidget::paintEvent(event); } diff --git a/src/kxyselector.cpp b/src/kxyselector.cpp index 772d048..96b4a5f 100644 --- a/src/kxyselector.cpp +++ b/src/kxyselector.cpp @@ -1,265 +1,264 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kxyselector.h" #include "loggingcategory.h" #include #include #include #include -#include //----------------------------------------------------------------------------- /* * 2D value selector. * The contents of the selector are drawn by derived class. */ class Q_DECL_HIDDEN KXYSelector::Private { public: Private(KXYSelector *q): q(q), xPos(0), yPos(0), minX(0), maxX(100), minY(0), maxY(100), m_markerColor(Qt::white) {} void setValues(int _xPos, int _yPos); KXYSelector *q; int px; int py; int xPos; int yPos; int minX; int maxX; int minY; int maxY; QColor m_markerColor; }; KXYSelector::KXYSelector(QWidget *parent) : QWidget(parent) , d(new Private(this)) { } KXYSelector::~KXYSelector() { delete d; } int KXYSelector::xValue() const { return d->xPos; } int KXYSelector::yValue() const { return d->yPos; } void KXYSelector::setRange(int _minX, int _minY, int _maxX, int _maxY) { if (_maxX == _minX) { qCWarning(KWidgetsAddonsLog) << "KXYSelector::setRange invalid range: " << _maxX << " == " << _minX << " (for X) "; return; } if (_maxY == _minY) { qCWarning(KWidgetsAddonsLog) << "KXYSelector::setRange invalid range: " << _maxY << " == " << _minY << " (for Y) "; return; } int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); d->px = w; d->py = w; d->minX = _minX; d->minY = _minY; d->maxX = _maxX; d->maxY = _maxY; } void KXYSelector::setXValue(int _xPos) { setValues(_xPos, d->yPos); } void KXYSelector::setYValue(int _yPos) { setValues(d->xPos, _yPos); } void KXYSelector::setValues(int _xPos, int _yPos) { d->setValues(_xPos, _yPos); } void KXYSelector::Private::setValues(int _xPos, int _yPos) { int w = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); xPos = _xPos; yPos = _yPos; if (xPos > maxX) { xPos = maxX; } else if (xPos < minX) { xPos = minX; } if (yPos > maxY) { yPos = maxY; } else if (yPos < minY) { yPos = minY; } Q_ASSERT(maxX != minX); int xp = w + (q->width() - 2 * w) * xPos / (maxX - minX); Q_ASSERT(maxY != minY); int yp = q->height() - w - (q->height() - 2 * w) * yPos / (maxY - minY); q->setPosition(xp, yp); } void KXYSelector::setMarkerColor(const QColor &col) { d->m_markerColor = col; } QRect KXYSelector::contentsRect() const { int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); return rect().adjusted(w, w, -w, -w); } QSize KXYSelector::minimumSizeHint() const { int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); return QSize(2 * w, 2 * w); } void KXYSelector::paintEvent(QPaintEvent * /* ev */) { QStyleOptionFrame opt; opt.initFrom(this); QPainter painter; painter.begin(this); drawContents(&painter); drawMarker(&painter, d->px, d->py); style()->drawPrimitive(QStyle::PE_Frame, &opt, &painter, this); painter.end(); } void KXYSelector::mousePressEvent(QMouseEvent *e) { mouseMoveEvent(e); } void KXYSelector::mouseMoveEvent(QMouseEvent *e) { int xVal, yVal; int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); valuesFromPosition(e->pos().x() - w, e->pos().y() - w, xVal, yVal); setValues(xVal, yVal); emit valueChanged(d->xPos, d->yPos); } void KXYSelector::wheelEvent(QWheelEvent *e) { if (e->orientation() == Qt::Horizontal) { setValues(xValue() + e->delta() / 120, yValue()); } else { setValues(xValue(), yValue() + e->delta() / 120); } emit valueChanged(d->xPos, d->yPos); } void KXYSelector::valuesFromPosition(int x, int y, int &xVal, int &yVal) const { int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); xVal = ((d->maxX - d->minX) * (x - w)) / (width() - 2 * w); yVal = d->maxY - (((d->maxY - d->minY) * (y - w)) / (height() - 2 * w)); if (xVal > d->maxX) { xVal = d->maxX; } else if (xVal < d->minX) { xVal = d->minX; } if (yVal > d->maxY) { yVal = d->maxY; } else if (yVal < d->minY) { yVal = d->minY; } } void KXYSelector::setPosition(int xp, int yp) { int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); if (xp < w) { xp = w; } else if (xp > width() - w) { xp = width() - w; } if (yp < w) { yp = w; } else if (yp > height() - w) { yp = height() - w; } d->px = xp; d->py = yp; update(); } void KXYSelector::drawContents(QPainter *) {} void KXYSelector::drawMarker(QPainter *p, int xp, int yp) { QPen pen(d->m_markerColor); p->setPen(pen); /* p->drawLine( xp - 6, yp - 6, xp - 2, yp - 2 ); p->drawLine( xp - 6, yp + 6, xp - 2, yp + 2 ); p->drawLine( xp + 6, yp - 6, xp + 2, yp - 2 ); p->drawLine( xp + 6, yp + 6, xp + 2, yp + 2 ); */ p->drawEllipse(xp - 4, yp - 4, 8, 8); } diff --git a/src/kxyselector.h b/src/kxyselector.h index 6a1d56e..96826aa 100644 --- a/src/kxyselector.h +++ b/src/kxyselector.h @@ -1,151 +1,150 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KXYSELECTOR_H #define KXYSELECTOR_H #include #include -#include /** * @class KXYSelector kxyselector.h KXYSelector * * KXYSelector is the base class for other widgets which * provides the ability to choose from a two-dimensional * range of values. The currently chosen value is indicated * by a cross. An example is the KHSSelector which * allows to choose from a range of colors, and which is * used in KColorDialog. * * A custom drawing routine for the widget surface has * to be provided by the subclass. */ class KWIDGETSADDONS_EXPORT KXYSelector : public QWidget { Q_OBJECT Q_PROPERTY(int xValue READ xValue WRITE setXValue) Q_PROPERTY(int yValue READ yValue WRITE setYValue) public: /** * Constructs a two-dimensional selector widget which * has a value range of [0..100] in both directions. */ explicit KXYSelector(QWidget *parent = nullptr); /** * Destructs the widget. */ ~KXYSelector() override; /** * Sets the current values in horizontal and * vertical direction. * @param xPos the horizontal value * @param yPos the vertical value */ void setValues(int xPos, int yPos); /** * Sets the current horizontal value * @param xPos the horizontal value */ void setXValue(int xPos); /** * Sets the current vertical value * @param yPos the vertical value */ void setYValue(int yPos); /** * Sets the range of possible values. */ void setRange(int minX, int minY, int maxX, int maxY); /** * Sets the color used to draw the marker * @param col the color */ void setMarkerColor(const QColor &col); /** * @return the current value in horizontal direction. */ int xValue() const; /** * @return the current value in vertical direction. */ int yValue() const; /** * @return the rectangle on which subclasses should draw. */ QRect contentsRect() const; /** * Reimplemented to give the widget a minimum size */ QSize minimumSizeHint() const override; Q_SIGNALS: /** * This signal is emitted whenever the user chooses a value, * e.g. by clicking with the mouse on the widget. */ void valueChanged(int x, int y); protected: /** * Override this function to draw the contents of the widget. * The default implementation does nothing. * * Draw within contentsRect() only. */ virtual void drawContents(QPainter *); /** * Override this function to draw the marker which * indicates the currently selected value pair. */ virtual void drawMarker(QPainter *p, int xp, int yp); void paintEvent(QPaintEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent *) override; /** * Converts a pixel position to its corresponding values. */ void valuesFromPosition(int x, int y, int &xVal, int &yVal) const; private: void setPosition(int xp, int yp); private: class Private; friend class Private; Private *const d; Q_DISABLE_COPY(KXYSelector) }; #endif /* KXYSELECTOR_H */ diff --git a/tests/kanimatedbuttontest.cpp b/tests/kanimatedbuttontest.cpp index d5ab536..fc47213 100644 --- a/tests/kanimatedbuttontest.cpp +++ b/tests/kanimatedbuttontest.cpp @@ -1,87 +1,86 @@ /* Copyright (c) 2008 Pino Toscano This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kanimatedbuttontest.h" #include "kanimatedbutton.h" #include -#include #include #include #include #include AnimationGroup::AnimationGroup(const QString &path, int size, QWidget *parent) : QGroupBox(parent) { QHBoxLayout *lay = new QHBoxLayout(this); m_animButton = new KAnimatedButton(this); lay->addWidget(m_animButton); QPushButton *start = new QPushButton(QStringLiteral("Start"), this); lay->addWidget(start); QPushButton *stop = new QPushButton(QStringLiteral("Stop"), this); lay->addWidget(stop); setTitle(QStringLiteral("%1 (%2)").arg(path).arg(size)); m_animButton->setIconSize(QSize(size, size)); m_animButton->setAnimationPath(path); connect(start, &QAbstractButton::clicked, m_animButton, &KAnimatedButton::start); connect(stop, &QAbstractButton::clicked, m_animButton, &KAnimatedButton::stop); } MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { QVBoxLayout *lay = new QVBoxLayout; setLayout(lay); QWidget *top = new QWidget(this); lay->addWidget(top); QHBoxLayout *lay2 = new QHBoxLayout(top); m_path = new QLineEdit(top); lay2->addWidget(m_path); m_size = new QSpinBox(top); lay2->addWidget(m_size); m_size->setValue(22); connect(m_path, &QLineEdit::returnPressed, this, &MainWindow::slotAddNew); } void MainWindow::slotAddNew() { AnimationGroup *group = new AnimationGroup(m_path->text(), m_size->value(), this); layout()->addWidget(group); } int main(int argc, char **argv) { QApplication::setApplicationName(QStringLiteral("kanimatedbuttontest")); QApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); MainWindow *window = new MainWindow(); window->show(); return app.exec(); } diff --git a/tests/kassistantdialogtest.cpp b/tests/kassistantdialogtest.cpp index 8fa2a00..b32fafa 100644 --- a/tests/kassistantdialogtest.cpp +++ b/tests/kassistantdialogtest.cpp @@ -1,50 +1,48 @@ /* * kassistantdialogtest - a test program for the KAssistantDialog class * Copyright (C) 1998 Thomas Tanghus (tanghus@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include -#include -//Added by qt3to4: -#include +#include #include int main(int argc, char **argv) { QApplication::setApplicationName(QStringLiteral("test")); QApplication a(argc, argv); a.setAttribute(Qt::AA_UseHighDpiPixmaps, true); KAssistantDialog *dlg = new KAssistantDialog(); QObject::connect(dlg, &QDialog::finished, &a, &QCoreApplication::quit); for (int i = 1; i < 11; i++) { QWidget *p = new QWidget; QString msg = QStringLiteral("This is page %1 out of 10").arg(i); QLabel *label = new QLabel(msg, p); QHBoxLayout *layout = new QHBoxLayout(p); label->setAlignment(Qt::AlignCenter); label->setFixedSize(300, 200); layout->addWidget(label); QString title = QStringLiteral("%1. page").arg(i); dlg->addPage(p, title); } dlg->show(); return a.exec(); } diff --git a/tests/kcollapsiblegroupboxtest.cpp b/tests/kcollapsiblegroupboxtest.cpp index b8f4fdb..b0e7725 100644 --- a/tests/kcollapsiblegroupboxtest.cpp +++ b/tests/kcollapsiblegroupboxtest.cpp @@ -1,93 +1,91 @@ /* This file is part of the KDE libraries * * Copyright 2015 David Edmundson * * Based on test program by Dominik Haumann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include -#include #include -#include #include #include #include "kdatepicker.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); QWidget mainWindow; QVBoxLayout mainWindowLayout(&mainWindow); //add a layout with many items to make sure it doesn't shuffle them weirdly when animating { auto groupBox = new KCollapsibleGroupBox; groupBox->setTitle(QStringLiteral("&Advanced Options")); auto innerLayout = new QVBoxLayout; for (int i =0; i<6;i++) { auto checkBox = new QCheckBox(QStringLiteral("Some text")); innerLayout->addWidget(checkBox); } auto checkBox = new QCheckBox(QStringLiteral("Some really long text that goes on and on and on for ever and ever")); innerLayout->addWidget(checkBox); auto label = new QLabel(groupBox); label->setText(QStringLiteral("Some input field:")); // Word-wrapping in labels triggers a bug in the layout positioning. label->setWordWrap(true); innerLayout->addWidget(label); auto lineEdit = new QLineEdit(groupBox); innerLayout->addWidget(lineEdit); auto hiddenCheckBox = new QCheckBox(QStringLiteral("This will be always hidden")); innerLayout->addWidget(hiddenCheckBox); hiddenCheckBox->hide(); groupBox->setLayout(innerLayout); mainWindowLayout.addWidget(groupBox); } //another item which should expand to fill width { auto groupBox = new KCollapsibleGroupBox; groupBox->setTitle(QStringLiteral("Pick a &date")); auto innerLayout = new QVBoxLayout; auto datePicker = new KDatePicker(); innerLayout->addWidget(datePicker); groupBox->setLayout(innerLayout); mainWindowLayout.addWidget(groupBox); } mainWindowLayout.addStretch(); mainWindow.setLayout(&mainWindowLayout); mainWindow.resize(400, 300); mainWindow.show(); return app.exec(); } // kate: replace-tabs on; diff --git a/tests/kcolorcombotest.cpp b/tests/kcolorcombotest.cpp index f48d4c4..fbd6c1e 100644 --- a/tests/kcolorcombotest.cpp +++ b/tests/kcolorcombotest.cpp @@ -1,156 +1,155 @@ /* This file is part of the KDE Libraries Copyright (c) 2007 David Jarvie This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcolorcombotest.h" #include #include -#include #include -#include #include - +#include +#include #include KColorComboTest::KColorComboTest(QWidget *widget) : QWidget(widget) { QVBoxLayout *vbox = new QVBoxLayout(this); QHBoxLayout *hboxLayout = new QHBoxLayout(this); // Standard color list QLabel *lbl = new QLabel(QStringLiteral("&Standard colors:"), this); lbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); mStandard = new KColorCombo(this); mStandard->setObjectName(QStringLiteral("StandardColors")); lbl->setBuddy(mStandard); QLabel *lblPreset = new QLabel(QStringLiteral("Preset to green (0,255,0)"), this); // add to box layout hboxLayout->addWidget(lbl); hboxLayout->addWidget(mStandard); hboxLayout->addWidget(lblPreset); vbox->addLayout(hboxLayout); hboxLayout = new QHBoxLayout(this); // Custom color list lbl = new QLabel(QStringLiteral("&Reds, greens, blues:"), this); lbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); mCustom = new KColorCombo(this); mCustom->setObjectName(QStringLiteral("CustomColors")); lbl->setBuddy(mCustom); lblPreset = new QLabel(QStringLiteral("Preset to green (0,192,0)"), this); // add to box layout hboxLayout->addWidget(lbl); hboxLayout->addWidget(mCustom); hboxLayout->addWidget(lblPreset); vbox->addLayout(hboxLayout); // Create an exit button mExit = new QPushButton(QStringLiteral("E&xit"), this); QObject::connect(mExit, &QAbstractButton::clicked, this, &KColorComboTest::quitApp); vbox->addWidget(mExit); // Populate the custom list QList standardList; standardList << Qt::red << Qt::green << Qt::blue << Qt::cyan << Qt::magenta << Qt::yellow << Qt::darkRed << Qt::darkGreen << Qt::darkBlue << Qt::darkCyan << Qt::darkMagenta << Qt::darkYellow << Qt::white << Qt::lightGray << Qt::gray << Qt::darkGray << Qt::black; QList list; list << QColor(255, 0, 0) << QColor(192, 0, 0) << QColor(128, 0, 0) << QColor(64, 0, 0) << QColor(0, 255, 0) << QColor(0, 192, 0) << QColor(0, 128, 0) << QColor(0, 64, 0) << QColor(0, 0, 255) << QColor(0, 0, 192) << QColor(0, 0, 128) << QColor(0, 0, 64); mCustom->setColors(list); if (mCustom->colors() != list) { qCritical() << "Custom combo: setColors() != colors()"; } mCustom->setColors(QList()); if (mCustom->colors() != standardList) { qCritical() << "Custom combo: setColors(empty) != standard colors"; } mCustom->setColors(list); if (mCustom->colors() != list) { qCritical() << "Custom combo: setColors() != colors()"; } if (mStandard->colors() != standardList) { qCritical() << "Standard combo: colors()"; } QColor col = QColor(1, 2, 3); mStandard->setColor(col); if (mStandard->color() != col) { qCritical() << "Standard combo: set custom color -> " << mStandard->color().red() << "," << mStandard->color().green() << "," << mStandard->color().blue(); } if (!mStandard->isCustomColor()) { qCritical() << "Standard combo: custom color: isCustomColor() -> false"; } mStandard->setColor(Qt::green); if (mStandard->color() != Qt::green) { qCritical() << "Standard combo: color() -> " << mStandard->color().red() << "," << mStandard->color().green() << "," << mStandard->color().blue(); } if (mStandard->isCustomColor()) { qCritical() << "Standard combo: standard color: isCustomColor() -> true"; } col = QColor(1, 2, 3); mCustom->setColor(col); if (mCustom->color() != col) { qCritical() << "Custom combo: set custom color -> " << mCustom->color().red() << "," << mCustom->color().green() << "," << mCustom->color().blue(); } if (!mCustom->isCustomColor()) { qCritical() << "Custom combo: custom color: isCustomColor() -> false"; } col = QColor(0, 192, 0); mCustom->setColor(col); if (mCustom->color() != col) { qCritical() << "Custom combo: color() -> " << mCustom->color().red() << "," << mCustom->color().green() << "," << mCustom->color().blue(); } if (mCustom->isCustomColor()) { qCritical() << "Custom combo: standard color: isCustomColor() -> true"; } } KColorComboTest::~KColorComboTest() { } void KColorComboTest::quitApp() { qApp->closeAllWindows(); } int main(int argc, char **argv) { QApplication a(argc, argv); a.setAttribute(Qt::AA_UseHighDpiPixmaps, true); KColorComboTest *t = new KColorComboTest; t->show(); return a.exec(); } diff --git a/tests/kdatepicktest.cpp b/tests/kdatepicktest.cpp index ae4f9e2..e2fc342 100644 --- a/tests/kdatepicktest.cpp +++ b/tests/kdatepicktest.cpp @@ -1,64 +1,63 @@ /* * Copyright 2014 Alex Merry * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include "kdatepicker.h" #include -#include #include class Manager : public QObject { Q_OBJECT public: Manager() { picker.show(); QTimer::singleShot(1000, this, SLOT(timeout1())); QTimer::singleShot(5000, this, SLOT(timeout2())); } private Q_SLOTS: void timeout1() { picker.setEnabled(false); } void timeout2() { picker.setEnabled(true); } private: KDatePicker picker; }; int main(int argc, char **argv) { QApplication::setApplicationName(QStringLiteral("KDatePickertest")); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QApplication app(argc, argv); Manager mgr; return app.exec(); } #include diff --git a/tests/knewpasswordwidget_test.cpp b/tests/knewpasswordwidget_test.cpp index 222e4de..00a1539 100644 --- a/tests/knewpasswordwidget_test.cpp +++ b/tests/knewpasswordwidget_test.cpp @@ -1,102 +1,101 @@ /* Copyright (c) 2016 Elvis Angelaccio This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "knewpasswordwidget_test.h" #include #include -#include #include #include #include #include #include // Doxygen will generate code snippets from this file. // We can't use i18n() here, but we want it to show up in the apidox. #define i18n QStringLiteral MyPasswordDialog::MyPasswordDialog(QWidget *parent) : QDialog(parent) { m_passwordWidget = new KNewPasswordWidget(this); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); m_passwordWidget->setMinimumPasswordLength(6); auto layout = new QVBoxLayout(this); layout->addWidget(m_passwordWidget); layout->addWidget(new QCheckBox(QStringLiteral("A checkbox"), this)); layout->addWidget(m_buttonBox); connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } //! [accept_custom_dialog] void MyPasswordDialog::accept() { switch (m_passwordWidget->passwordStatus()) { case KNewPasswordWidget::WeakPassword: case KNewPasswordWidget::StrongPassword: QDialog::accept(); break; case KNewPasswordWidget::PasswordNotVerified: KMessageBox::error(nullptr, i18n("The chosen password does not match the given verification password.")); break; case KNewPasswordWidget::EmptyPasswordNotAllowed: KMessageBox::error(nullptr, i18n("The chosen password cannot be empty.")); break; case KNewPasswordWidget::PasswordTooShort: KMessageBox::error(nullptr, i18n("The chosen password is too short.")); break; } } //! [accept_custom_dialog] //! [update_custom_dialog] void MyPasswordDialog::slotPasswordStatusChanged() { // You may want to extend this switch with more cases, // in order to warn the user about all the possible password issues. switch (m_passwordWidget->passwordStatus()) { case KNewPasswordWidget::WeakPassword: case KNewPasswordWidget::StrongPassword: m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); break; default: m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); break; } } //! [update_custom_dialog] int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); MyPasswordDialog dialog; QObject::connect(&dialog, &QDialog::finished, &app, &QCoreApplication::quit); dialog.show(); return app.exec(); } diff --git a/tests/kseparatortest.cpp b/tests/kseparatortest.cpp index ecd3154..8925ffd 100644 --- a/tests/kseparatortest.cpp +++ b/tests/kseparatortest.cpp @@ -1,46 +1,45 @@ /* * Copyright (C) 1997 Michael Roth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include -#include #include #include #include "kseparator.h" int main(int argc, char **argv) { QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QApplication app(argc, argv); QWidget toplevel; QBoxLayout *mainbox = new QBoxLayout(QBoxLayout::TopToBottom, &toplevel); mainbox->setContentsMargins(10, 10, 10, 10); KSeparator *sep1 = new KSeparator(Qt::Vertical, &toplevel); mainbox->addWidget(sep1); KSeparator *sep2 = new KSeparator(Qt::Horizontal, &toplevel); mainbox->addWidget(sep2); mainbox->activate(); toplevel.show(); return app.exec(); } diff --git a/tests/ktoolbarlabelactiontest.cpp b/tests/ktoolbarlabelactiontest.cpp index 3a2c88d..afda7a9 100644 --- a/tests/ktoolbarlabelactiontest.cpp +++ b/tests/ktoolbarlabelactiontest.cpp @@ -1,92 +1,91 @@ /* This file is part of the KDE libraries Copyright 2013 Benjamin Port This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include #include -#include #include #include #include #include class MainWindow : public QMainWindow { Q_OBJECT private Q_SLOTS: void updateLabel1() { label1->setText(labelText->text()); } public: MainWindow() { QWidget *mainWidget = new QWidget(this); setCentralWidget(mainWidget); QVBoxLayout *layout = new QVBoxLayout(mainWidget); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); QToolBar *toolBar = addToolBar(QStringLiteral("Toolbar")); labelText = new QLineEdit(); QPushButton *validateButton = new QPushButton(QStringLiteral("Update label")); layout->addWidget(labelText); layout->addWidget(validateButton); connect(validateButton, &QAbstractButton::clicked, this, &MainWindow::updateLabel1); QWidgetAction *lineEditAction2 = new QWidgetAction(toolBar); QLineEdit *lineEdit2 = new QLineEdit; lineEditAction2->setDefaultWidget(lineEdit2); label1 = new KToolBarLabelAction(QStringLiteral("&Label 1"), toolBar); label2 = new KToolBarLabelAction(lineEditAction2, QStringLiteral("&Second label"), toolBar); QWidgetAction *lineEditAction = new QWidgetAction(toolBar); QLineEdit *lineEdit = new QLineEdit; lineEditAction->setDefaultWidget(lineEdit); // set buddy for label1 label1->setBuddy(lineEditAction); toolBar->addAction(label1); toolBar->addAction(lineEditAction); toolBar->addAction(label2); toolBar->addAction(lineEditAction2); } QLineEdit *labelText; KToolBarLabelAction *label1; KToolBarLabelAction *label2; }; int main(int argc, char **argv) { QApplication::setApplicationName(QStringLiteral("Test KToolBarLabelAction")); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QApplication app(argc, argv); MainWindow *window = new MainWindow; window->show(); return app.exec(); } #include "ktoolbarlabelactiontest.moc" diff --git a/tests/ktooltipwidget_test.cpp b/tests/ktooltipwidget_test.cpp index f0080e7..5acf3ca 100644 --- a/tests/ktooltipwidget_test.cpp +++ b/tests/ktooltipwidget_test.cpp @@ -1,77 +1,76 @@ /* * Copyright (c) 2017 Elvis Angelaccio * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "ktooltipwidget_test.h" #include #include -#include #include #include #include // Doxygen will generate code snippets from this file. // We can't use i18n() here, but we want it to show up in the apidox. #define i18n QStringLiteral TestDialog::TestDialog(QWidget *parent) : QDialog(parent) { m_view.setColumnCount(1); m_view.setRootIsDecorated(false); m_view.setMouseTracking(true); auto item = new QTreeWidgetItem(&m_view); item->setText(0, QStringLiteral("Hover me! (first item)")); auto item2 = new QTreeWidgetItem(&m_view); item2->setText(0, QStringLiteral("Hover me! (second item)")); auto spinBox = new QSpinBox(this); spinBox->setPrefix(QStringLiteral("Hide delay (ms): ")); spinBox->setMaximum(5000); spinBox->setValue(500); connect(spinBox, static_cast(&QSpinBox::valueChanged), &m_tooltipWidget, &KToolTipWidget::setHideDelay); auto layout = new QVBoxLayout(this); layout->addWidget(spinBox); layout->addWidget(&m_view); //! [show_tooltip_widget] connect(&m_view, &QAbstractItemView::entered, this, [=](const QModelIndex &index) { auto rect = m_view.visualRect(index); const auto pos = m_view.viewport()->mapToGlobal(rect.topLeft()); rect.moveTo(pos); auto button = new QPushButton(i18n("Push me (row %1)").arg(index.row()), this); m_tooltipWidget.showBelow(rect, button, m_view.nativeParentWidget()->windowHandle()); }); //! [show_tooltip_widget] connect(&m_view, &QAbstractItemView::viewportEntered, &m_tooltipWidget, &KToolTipWidget::hideLater); } int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); TestDialog dialog; QObject::connect(&dialog, &QDialog::finished, &app, &QCoreApplication::quit); dialog.show(); return app.exec(); }