[yast-commit] r44036 - in /branches/tmp/tgoettlicher/yast2cc_rewrite: ./ package/ src/
Author: tgoettlicher Date: Thu Jan 31 11:10:23 2008 New Revision: 44036 URL: http://svn.opensuse.org/viewcvs/yast?rev=44036&view=rev Log: initial checkin Added: branches/tmp/tgoettlicher/yast2cc_rewrite/CMakeLists.txt branches/tmp/tgoettlicher/yast2cc_rewrite/MAINTAINER branches/tmp/tgoettlicher/yast2cc_rewrite/Makefile.cvs branches/tmp/tgoettlicher/yast2cc_rewrite/VERSION.cmake branches/tmp/tgoettlicher/yast2cc_rewrite/package/ branches/tmp/tgoettlicher/yast2cc_rewrite/src/ branches/tmp/tgoettlicher/yast2cc_rewrite/src/CMakeLists.txt branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel_p.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview_p.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/main.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.cpp branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.h branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettings.desktop branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsrc branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsui.rc Added: branches/tmp/tgoettlicher/yast2cc_rewrite/CMakeLists.txt URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/CMakeLists.txt?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/CMakeLists.txt (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/CMakeLists.txt Thu Jan 31 11:10:23 2008 @@ -0,0 +1,7 @@ +PROJECT( yast2-control-center ) +CMAKE_MINIMUM_REQUIRED( VERSION 2.4.0 ) +FIND_PACKAGE( Qt4 REQUIRED ) + +SET( RPMNAME "yast2-control-center" ) + +ADD_SUBDIRECTORY( src ) Added: branches/tmp/tgoettlicher/yast2cc_rewrite/MAINTAINER URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/MAINTAINER?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/MAINTAINER (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/MAINTAINER Thu Jan 31 11:10:23 2008 @@ -0,0 +1 @@ +Thomas Goettlicher <tgoettlicher@suse.de> Added: branches/tmp/tgoettlicher/yast2cc_rewrite/Makefile.cvs URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/Makefile.cvs?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/Makefile.cvs (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/Makefile.cvs Thu Jan 31 11:10:23 2008 @@ -0,0 +1,18 @@ +# +# Makefile.cvs +# + +PREFIX = /usr + +configure: + mkdir build ;\ + cd build ;\ + cmake -DCMAKE_INSTALL_PREFIX=$(PREFIX) + +install: configure + cd build ;\ + make && make install + +reconf: + cd build ;\ + cmake rebuild_cache Added: branches/tmp/tgoettlicher/yast2cc_rewrite/VERSION.cmake URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/VERSION.cmake?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/VERSION.cmake (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/VERSION.cmake Thu Jan 31 11:10:23 2008 @@ -0,0 +1,3 @@ +SET(VERSION_MAJOR "0") +SET(VERSION_MINOR "0") +SET(VERSION_PATCH "1") Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/CMakeLists.txt URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/CMakeLists.txt?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/CMakeLists.txt (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/CMakeLists.txt Thu Jan 31 11:10:23 2008 @@ -0,0 +1,50 @@ +INCLUDE(${QT_USE_FILE}) + +INCLUDE_DIRECTORIES(/usr/include/initng ${CMAKE_CURRENT_BINARY_DIR}) + +SET(yast2-control-center_SRCS + main.cpp + main_window.cpp + +kcategorizedview.cpp +menuitem.cpp +kcategorydrawer.cpp +kcategorizedsortfilterproxymodel.cpp +kcmodulemodel.cpp + + +) + +#SET(yast2-control-center_UIS +# main_window.ui +#) + +SET(yast2-control-center_HDRS + main_window.h +kcategorizedview.h +menuitem.h +kcmodulemodel.h +kcategorydrawer.h +kcategorizedsortfilterproxymodel.h + +) + +#SET(yast2-control-center_RCCS ../files.qrc) + + +QT4_AUTOMOC(${yast2-control-center_SRCS}) + +# QT4_WRAP_UI(yast2-control-center_UIS_H ${yast2-control-center_UIS}) + +QT4_WRAP_CPP(yast2-control-center_MOC ${yast2-control-center_UIS_H}) + +QT4_ADD_RESOURCES(yast2-control-center_RCC_SRCS ${yast2-control-center_RCCS}) + +ADD_DEFINITIONS(-DQT_NO_DEBUG) + + +ADD_EXECUTABLE(yast2-control-center ${yast2-control-center_SRCS} ${yast2-control-center_MOC} ${yast2-control-center_RCC_SRCS}) + +TARGET_LINK_LIBRARIES(yast2-control-center ${QT_LIBRARIES}) + +INSTALL(TARGETS yast2-control-center DESTINATION bin) Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,288 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org> + * Copyright (C) 2007 John Tapsell <tapsell@kde.org> + * Copyright (C) 2006 by Dominic Battre <dominic@battre.de> + * Copyright (C) 2006 by Martin Pool <mbp@canonical.com> + * + * 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 "kcategorizedsortfilterproxymodel.h" +#include "kcategorizedsortfilterproxymodel_p.h" + +#include <limits.h> + +#include <QItemSelection> +#include <QStringList> +#include <QSize> + +KCategorizedSortFilterProxyModel::KCategorizedSortFilterProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) + , d(new Private()) + +{ +} + +KCategorizedSortFilterProxyModel::~KCategorizedSortFilterProxyModel() +{ + delete d; +} + +void KCategorizedSortFilterProxyModel::sort(int column, Qt::SortOrder order) +{ + d->sortColumn = column; + d->sortOrder = order; + + QSortFilterProxyModel::sort(column, order); +} + +bool KCategorizedSortFilterProxyModel::isCategorizedModel() const +{ + return d->categorizedModel; +} + +void KCategorizedSortFilterProxyModel::setCategorizedModel(bool categorizedModel) +{ + if (categorizedModel == d->categorizedModel) + { + return; + } + + d->categorizedModel = categorizedModel; + + invalidate(); +} + +int KCategorizedSortFilterProxyModel::sortColumn() const +{ + return d->sortColumn; +} + +Qt::SortOrder KCategorizedSortFilterProxyModel::sortOrder() const +{ + return d->sortOrder; +} + +void KCategorizedSortFilterProxyModel::setSortCategoriesByNaturalComparison(bool sortCategoriesByNaturalComparison) +{ + if (sortCategoriesByNaturalComparison == d->sortCategoriesByNaturalComparison) + { + return; + } + + d->sortCategoriesByNaturalComparison = sortCategoriesByNaturalComparison; + + invalidate(); +} + +bool KCategorizedSortFilterProxyModel::sortCategoriesByNaturalComparison() const +{ + return d->sortCategoriesByNaturalComparison; +} + +int KCategorizedSortFilterProxyModel::naturalCompare(const QString &a, + const QString &b) +{ + // This method chops the input a and b into pieces of + // digits and non-digits (a1.05 becomes a | 1 | . | 05) + // and compares these pieces of a and b to each other + // (first with first, second with second, ...). + // + // This is based on the natural sort order code code by Martin Pool + // http://sourcefrog.net/projects/natsort/ + // Martin Pool agreed to license this under LGPL or GPL. + + const QChar* currA = a.unicode(); // iterator over a + const QChar* currB = b.unicode(); // iterator over b + + if (currA == currB) { + return 0; + } + + const QChar* begSeqA = currA; // beginning of a new character sequence of a + const QChar* begSeqB = currB; + + while (!currA->isNull() && !currB->isNull()) { + if (currA->unicode() == QChar::ObjectReplacementCharacter) { + return 1; + } + + if (currB->unicode() == QChar::ObjectReplacementCharacter) { + return -1; + } + + if (currA->unicode() == QChar::ReplacementCharacter) { + return 1; + } + + if (currB->unicode() == QChar::ReplacementCharacter) { + return -1; + } + + // find sequence of characters ending at the first non-character + while (!currA->isNull() && !currA->isDigit()) { + ++currA; + } + + while (!currB->isNull() && !currB->isDigit()) { + ++currB; + } + + // compare these sequences + const QString subA(begSeqA, currA - begSeqA); + const QString subB(begSeqB, currB - begSeqB); + const int cmp = QString::localeAwareCompare(subA, subB); + if (cmp != 0) { + return cmp; + } + + if (currA->isNull() || currB->isNull()) { + break; + } + + // now some digits follow... + if ((*currA == '0') || (*currB == '0')) { + // one digit-sequence starts with 0 -> assume we are in a fraction part + // do left aligned comparison (numbers are considered left aligned) + while (1) { + if (!currA->isDigit() && !currB->isDigit()) { + break; + } else if (!currA->isDigit()) { + return -1; + } else if (!currB->isDigit()) { + return + 1; + } else if (*currA < *currB) { + return -1; + } else if (*currA > *currB) { + return + 1; + } + ++currA; + ++currB; + } + } else { + // No digit-sequence starts with 0 -> assume we are looking at some integer + // do right aligned comparison. + // + // The longest run of digits wins. That aside, the greatest + // value wins, but we can't know that it will until we've scanned + // both numbers to know that they have the same magnitude. + + int weight = 0; + while (1) { + if (!currA->isDigit() && !currB->isDigit()) { + if (weight != 0) { + return weight; + } + break; + } else if (!currA->isDigit()) { + return -1; + } else if (!currB->isDigit()) { + return + 1; + } else if ((*currA < *currB) && (weight == 0)) { + weight = -1; + } else if ((*currA > *currB) && (weight == 0)) { + weight = + 1; + } + ++currA; + ++currB; + } + } + + begSeqA = currA; + begSeqB = currB; + } + + if (currA->isNull() && currB->isNull()) { + return 0; + } + + return currA->isNull() ? -1 : + 1; +} + +bool KCategorizedSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + if (d->categorizedModel) + { + int compare = compareCategories(left, right); + + if (compare > 0) // left is greater than right + { + return false; + } + else if (compare < 0) // left is less than right + { + return true; + } + } + + return subSortLessThan(left, right); +} + +bool KCategorizedSortFilterProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const +{ + return QSortFilterProxyModel::lessThan(left, right); +} + +int KCategorizedSortFilterProxyModel::compareCategories(const QModelIndex &left, const QModelIndex &right) const +{ + QVariant l = (left.model() ? left.model()->data(left, CategorySortRole) : QVariant()); + QVariant r = (right.model() ? right.model()->data(right, CategorySortRole) : QVariant()); + + Q_ASSERT(l.isValid()); + Q_ASSERT(r.isValid()); + Q_ASSERT(l.type() == r.type()); + + if (l.type() == QVariant::String) + { + QString lstr = l.toString(); + QString rstr = r.toString(); + + if (d->sortCategoriesByNaturalComparison) + { + return naturalCompare(lstr, rstr); + } + else + { + if (lstr < rstr) + { + return -1; + } + + if (lstr > rstr) + { + return 1; + } + + return 0; + } + } + + qlonglong lint = l.toLongLong(); + qlonglong rint = r.toLongLong(); + + if (lint < rint) + { + return -1; + } + + if (lint > rint) + { + return 1; + } + + return 0; +} Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,184 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org> + * Copyright (C) 2007 John Tapsell <tapsell@kde.org> + * Copyright (C) 2006 by Dominic Battre <dominic@battre.de> + * Copyright (C) 2006 by Martin Pool <mbp@canonical.com> + * + * 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 KCATEGORIZEDSORTFILTERPROXYMODEL_H +#define KCATEGORIZEDSORTFILTERPROXYMODEL_H + +#include <QtGui/QSortFilterProxyModel> + +//#include "kdeui_export.h" + +class QItemSelection; + + +/** + * This class lets you categorize a view. It is meant to be used along with + * KCategorizedView class. + * + * In general terms all you need to do is to reimplement subSortLessThan() and + * compareCategories() methods. In order to make categorization work, you need + * to also call setCategorizedModel() class to enable it, since the categorization + * is disabled by default. + * + * @see KCategorizedView + * + * @author Rafael Fernández López <ereslibre@kde.org> + */ +//class KDEUI_EXPORT KCategorizedSortFilterProxyModel +class KCategorizedSortFilterProxyModel + : public QSortFilterProxyModel +{ +public: + enum AdditionalRoles { + // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) + // to define additional roles. + CategoryDisplayRole = 0x17CE990A, ///< This role is used for asking the category to a given index + + CategorySortRole = 0x27857E60 ///< This role is used for sorting categories. You can return a + ///< string or a long long value. Strings will be sorted alphabetically + ///< while long long will be sorted by their value. Please note that this + ///< value won't be shown on the view, is only for sorting purposes. What will + ///< be shown as "Category" on the view will be asked with the role + ///< CategoryDisplayRole. + }; + + KCategorizedSortFilterProxyModel(QObject *parent = 0); + virtual ~KCategorizedSortFilterProxyModel(); + + /** + * Overridden from QSortFilterProxyModel. Sorts the source model using + * @p column for the given @p order. + */ + virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); + + /** + * @return whether the model is categorized or not. Disabled by default. + */ + bool isCategorizedModel() const; + + /** + * Enables or disables the categorization feature. + * + * @param categorizedModel whether to enable or disable the categorization feature. + */ + void setCategorizedModel(bool categorizedModel); + + /** + * @return the column being used for sorting. + */ + int sortColumn() const; + + /** + * @return the sort order being used for sorting. + */ + Qt::SortOrder sortOrder() const; + + /** + * Set if the sorting using CategorySortRole will use a natural comparison + * in the case that strings were returned. If enabled, QString::localeAwareCompare + * will be used for sorting. + * + * @param sortCategoriesByNaturalComparison whether to sort using a natural comparison or not. + */ + void setSortCategoriesByNaturalComparison(bool sortCategoriesByNaturalComparison); + + /** + * @return whether it is being used a natural comparison for sorting. Enabled by default. + */ + bool sortCategoriesByNaturalComparison() const; + + /** + * Does a natural comparing of the strings. -1 is returned if \a a + * is smaller than \a b. +1 is returned if \a a is greater than \a b. 0 + * is returned if both values are equal. + */ + static int naturalCompare(const QString &a, const QString &b); + +protected: + /** + * Overridden from QSortFilterProxyModel. If you are subclassing + * KCategorizedSortFilterProxyModel, you will probably not need to reimplement this + * method. + * + * It calls compareCategories() to sort by category. If the both items are in the + * same category (i.e. compareCategories returns 0), then subSortLessThan is called. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + * + * @warning You usually won't need to reimplement this method when subclassing + * from KCategorizedSortFilterProxyModel. + */ + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + + /** + * This method has a similar purpose as lessThan() has on QSortFilterProxyModel. + * It is used for sorting items that are in the same category. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + */ + virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; + + /** + * This method compares the category of the @p left index with the category + * of the @p right index. + * + * Internally and if not reimplemented, this method will ask for @p left and + * @p right models for role CategorySortRole. In order to correctly sort + * categories, the data() metod of the model should return a qlonglong (or numeric) value, or + * a QString object. QString objects will be sorted with QString::localeAwareCompare if + * sortCategoriesByNaturalComparison() is true. + * + * @note Please have present that: + * QString(QChar(QChar::ObjectReplacementCharacter)) > + * QString(QChar(QChar::ReplacementCharacter)) > + * [ all possible strings ] > + * QString(); + * + * This means that QString() will be sorted the first one, while + * QString(QChar(QChar::ObjectReplacementCharacter)) and + * QString(QChar(QChar::ReplacementCharacter)) will be sorted in last + * position. + * + * @warning Please note that data() method of the model should return always + * information of the same type. If you return a QString for an index, + * you should return always QStrings for all indexes for role CategorySortRole + * in order to correctly sort categories. You can't mix by returning + * a QString for one index, and a qlonglong for other. + * + * @note If you need a more complex layout, you will have to reimplement this + * method. + * + * @return A negative value if the category of @p left should be placed before the + * category of @p right. 0 if @p left and @p right are on the same category, and + * a positive value if the category of @p left should be placed after the + * category of @p right. + */ + virtual int compareCategories(const QModelIndex &left, const QModelIndex &right) const; + +private: + class Private; + Private *const d; +}; + + +#endif // KCATEGORIZEDSORTFILTERPROXYMODEL_H Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel_p.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel_p.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel_p.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedsortfilterproxymodel_p.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,48 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org> + * Copyright (C) 2007 John Tapsell <tapsell@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 KCATEGORIZEDSORTFILTERPROXYMODEL_P_H +#define KCATEGORIZEDSORTFILTERPROXYMODEL_P_H + +class KCategorizedSortFilterProxyModel; + +class KCategorizedSortFilterProxyModel::Private +{ +public: + Private() + : sortColumn(0) + , sortOrder(Qt::AscendingOrder) + , categorizedModel(false) + , sortCategoriesByNaturalComparison(true) + { + } + + ~Private() + { + } + + int sortColumn; + Qt::SortOrder sortOrder; + bool categorizedModel; + bool sortCategoriesByNaturalComparison; +}; + +#endif Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,1634 @@ +/** + * This file is part of the KDE project + * 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 "kcategorizedview.h" +#include "kcategorizedview_p.h" + +#include <math.h> // trunc on C99 compliant systems +#include <kdefakes.h> // trunc for not C99 compliant systems + +#include <QPainter> +#include <QScrollBar> +#include <QPaintEvent> + +//#include <kstyle.h> + +#include "kcategorydrawer.h" +#include "kcategorizedsortfilterproxymodel.h" + +// By defining DOLPHIN_DRAGANDDROP the custom drag and drop implementation of +// KCategorizedView is bypassed to have a consistent drag and drop look for all +// views. Hopefully transparent pixmaps for drag objects will be supported in +// Qt 4.4, so that this workaround can be skipped. +#define DOLPHIN_DRAGANDDROP + +KCategorizedView::Private::Private(KCategorizedView *listView) + : listView(listView) + , categoryDrawer(0) + , biggestItemSize(QSize(0, 0)) + , mouseButtonPressed(false) + , rightMouseButtonPressed(false) + , isDragging(false) + , dragLeftViewport(false) + , proxyModel(0) +{ +} + +KCategorizedView::Private::~Private() +{ +} + +const QModelIndexList &KCategorizedView::Private::intersectionSet(const QRect &rect) +{ + QModelIndex index; + QRect indexVisualRect; + + intersectedIndexes.clear(); + + int itemHeight; + + if (listView->gridSize().isEmpty()) + { + itemHeight = biggestItemSize.height(); + } + else + { + itemHeight = listView->gridSize().height(); + } + + // Lets find out where we should start + int top = proxyModel->rowCount() - 1; + int bottom = 0; + int middle = (top + bottom) / 2; + while (bottom <= top) + { + middle = (top + bottom) / 2; + + index = proxyModel->index(middle, 0); + indexVisualRect = visualRect(index); + // We need the whole height (not only the visualRect). This will help us to update + // all needed indexes correctly (ereslibre) + indexVisualRect.setHeight(indexVisualRect.height() + (itemHeight - indexVisualRect.height())); + + if (qMax(indexVisualRect.topLeft().y(), + indexVisualRect.bottomRight().y()) < qMin(rect.topLeft().y(), + rect.bottomRight().y())) + { + bottom = middle + 1; + } + else + { + top = middle - 1; + } + } + + for (int i = middle; i < proxyModel->rowCount(); i++) + { + index = proxyModel->index(i, 0); + indexVisualRect = visualRect(index); + + if (rect.intersects(indexVisualRect)) + intersectedIndexes.append(index); + + // If we passed next item, stop searching for hits + if (qMax(rect.bottomRight().y(), rect.topLeft().y()) < + qMin(indexVisualRect.topLeft().y(), + indexVisualRect.bottomRight().y())) + break; + } + + return intersectedIndexes; +} + +QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index) const +{ + if (!index.isValid()) + return QRect(); + + QString curCategory = elementsInfo[index.row()].category; + + QRect retRect; + + if (listView->flow() == QListView::LeftToRight) + { + if (listView->layoutDirection() == Qt::LeftToRight) + { + retRect = QRect(listView->spacing(), listView->spacing() * 2 + + categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0); + } + else + { + retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 + + categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0); + } + } + else + { + retRect = QRect(listView->spacing(), listView->spacing() * 2 + + categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0); + } + + int viewportWidth = listView->viewport()->width() - listView->spacing(); + + int itemHeight; + int itemWidth; + + if (listView->gridSize().isEmpty() && (listView->flow() == QListView::LeftToRight)) + { + itemHeight = biggestItemSize.height(); + itemWidth = biggestItemSize.width(); + } + else if (listView->flow() == QListView::LeftToRight) + { + itemHeight = listView->gridSize().height(); + itemWidth = listView->gridSize().width(); + } + else if (listView->gridSize().isEmpty() && (listView->flow() == QListView::TopToBottom)) + { + itemHeight = biggestItemSize.height(); + itemWidth = listView->viewport()->width() - listView->spacing() * 2; + } + else + { + itemHeight = listView->gridSize().height(); + itemWidth = listView->gridSize().width() - listView->spacing() * 2; + } + + int itemWidthPlusSeparation = listView->spacing() + itemWidth; + if (!itemWidthPlusSeparation) + itemWidthPlusSeparation++; + int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + if (!elementsPerRow) + elementsPerRow++; + + int column; + int row; + + if (listView->flow() == QListView::LeftToRight) + { + column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow; + row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow; + + if (listView->layoutDirection() == Qt::LeftToRight) + { + retRect.setLeft(retRect.left() + column * listView->spacing() + + column * itemWidth); + } + else + { + retRect.setLeft(retRect.right() - column * listView->spacing() - + column * itemWidth - itemWidth); + + retRect.setRight(retRect.right() - column * listView->spacing() - + column * itemWidth); + } + } + else + { + elementsPerRow = 1; + column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow; + row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow; + } + + foreach (const QString &category, categories) + { + if (category == curCategory) + break; + + float rows = (float) ((float) categoriesIndexes[category].count() / + (float) elementsPerRow); + + int rowsInt = categoriesIndexes[category].count() / elementsPerRow; + + if (rows - trunc(rows)) rowsInt++; + + retRect.setTop(retRect.top() + + (rowsInt * itemHeight) + + categoryDrawer->categoryHeight(index, listView->viewOptions()) + + listView->spacing() * 2); + + if (listView->gridSize().isEmpty()) + { + retRect.setTop(retRect.top() + + (rowsInt * listView->spacing())); + } + } + + if (listView->gridSize().isEmpty()) + { + retRect.setTop(retRect.top() + row * listView->spacing() + + (row * itemHeight)); + } + else + { + retRect.setTop(retRect.top() + (row * itemHeight)); + } + + retRect.setWidth(itemWidth); + + QModelIndex heightIndex = proxyModel->index(index.row(), 0); + if (listView->gridSize().isEmpty()) + { + retRect.setHeight(listView->sizeHintForIndex(heightIndex).height()); + } + else + { + retRect.setHeight(qMin(listView->sizeHintForIndex(heightIndex).height(), + listView->gridSize().height())); + } + + return retRect; +} + +QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &category) const +{ + QRect retRect(listView->spacing(), + listView->spacing(), + listView->viewport()->width() - listView->spacing() * 2, + 0); + + if (!proxyModel->rowCount() || !categories.contains(category)) + return QRect(); + + QModelIndex index = proxyModel->index(0, 0, QModelIndex()); + + int viewportWidth = listView->viewport()->width() - listView->spacing(); + + int itemHeight; + int itemWidth; + + if (listView->gridSize().isEmpty()) + { + itemHeight = biggestItemSize.height(); + itemWidth = biggestItemSize.width(); + } + else + { + itemHeight = listView->gridSize().height(); + itemWidth = listView->gridSize().width(); + } + + int itemWidthPlusSeparation = listView->spacing() + itemWidth; + int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + + if (!elementsPerRow) + elementsPerRow++; + + if (listView->flow() == QListView::TopToBottom) + { + elementsPerRow = 1; + } + + foreach (const QString &itCategory, categories) + { + if (itCategory == category) + break; + + float rows = (float) ((float) categoriesIndexes[itCategory].count() / + (float) elementsPerRow); + int rowsInt = categoriesIndexes[itCategory].count() / elementsPerRow; + + if (rows - trunc(rows)) rowsInt++; + + retRect.setTop(retRect.top() + + (rowsInt * itemHeight) + + categoryDrawer->categoryHeight(index, listView->viewOptions()) + + listView->spacing() * 2); + + if (listView->gridSize().isEmpty()) + { + retRect.setTop(retRect.top() + + (rowsInt * listView->spacing())); + } + } + + retRect.setHeight(categoryDrawer->categoryHeight(index, listView->viewOptions())); + + return retRect; +} + +// We're sure elementsPosition doesn't contain index +const QRect &KCategorizedView::Private::cacheIndex(const QModelIndex &index) +{ + QRect rect = visualRectInViewport(index); + elementsPosition[index.row()] = rect; + + return elementsPosition[index.row()]; +} + +// We're sure categoriesPosition doesn't contain category +const QRect &KCategorizedView::Private::cacheCategory(const QString &category) +{ + QRect rect = visualCategoryRectInViewport(category); + categoriesPosition[category] = rect; + + return categoriesPosition[category]; +} + +const QRect &KCategorizedView::Private::cachedRectIndex(const QModelIndex &index) +{ + if (elementsPosition.contains(index.row())) // If we have it cached + { // return it + return elementsPosition[index.row()]; + } + else // Otherwise, cache it + { // and return it + return cacheIndex(index); + } +} + +const QRect &KCategorizedView::Private::cachedRectCategory(const QString &category) +{ + if (categoriesPosition.contains(category)) // If we have it cached + { // return it + return categoriesPosition[category]; + } + else // Otherwise, cache it and + { // return it + return cacheCategory(category); + } +} + +QRect KCategorizedView::Private::visualRect(const QModelIndex &index) +{ + QRect retRect = cachedRectIndex(index); + int dx = -listView->horizontalOffset(); + int dy = -listView->verticalOffset(); + retRect.adjust(dx, dy, dx, dy); + + return retRect; +} + +QRect KCategorizedView::Private::categoryVisualRect(const QString &category) +{ + QRect retRect = cachedRectCategory(category); + int dx = -listView->horizontalOffset(); + int dy = -listView->verticalOffset(); + retRect.adjust(dx, dy, dx, dy); + + return retRect; +} + +void KCategorizedView::Private::drawNewCategory(const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter) +{ + if (!index.isValid()) + { + return; + } + + QStyleOption optionCopy = option; + const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + + optionCopy.state &= ~QStyle::State_Selected; + + if ((listView->selectionMode() != SingleSelection) && (listView->selectionMode() != NoSelection)) { + if ((category == hoveredCategory) && !mouseButtonPressed) + { + optionCopy.state |= QStyle::State_MouseOver; + } + else if ((category == hoveredCategory) && mouseButtonPressed) + { + QPoint initialPressPosition = listView->viewport()->mapFromGlobal(QCursor::pos()); + initialPressPosition.setY(initialPressPosition.y() + listView->verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() + listView->horizontalOffset()); + + if (initialPressPosition == this->initialPressPosition) + { + optionCopy.state |= QStyle::State_Selected; + } + } + } + + categoryDrawer->drawCategory(index, + sortRole, + optionCopy, + painter); +} + + +void KCategorizedView::Private::updateScrollbars() +{ + // find the last index in the last category + QModelIndex lastIndex = categoriesIndexes.isEmpty() ? QModelIndex() : categoriesIndexes[categories.last()].last(); + + int lastItemBottom = cachedRectIndex(lastIndex).top() + + listView->spacing() + (listView->gridSize().isEmpty() ? biggestItemSize.height() : listView->gridSize().height()) - listView->viewport()->height(); + + listView->horizontalScrollBar()->setRange(0, 0); + + if (listView->verticalScrollMode() == QAbstractItemView::ScrollPerItem) + { + listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + } + + if (listView->horizontalScrollMode() == QAbstractItemView::ScrollPerItem) + { + listView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + } + + listView->verticalScrollBar()->setSingleStep(listView->viewport()->height() / 10); + listView->verticalScrollBar()->setPageStep(listView->viewport()->height()); + listView->verticalScrollBar()->setRange(0, lastItemBottom); +} + +void KCategorizedView::Private::drawDraggedItems(QPainter *painter) +{ + QStyleOptionViewItemV3 option = listView->viewOptions(); + option.state &= ~QStyle::State_MouseOver; + foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes()) + { + const int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset(); + const int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset(); + + option.rect = visualRect(index); + option.rect.adjust(dx, dy, dx, dy); + + if (option.rect.intersects(listView->viewport()->rect())) + { + listView->itemDelegate(index)->paint(painter, option, index); + } + } +} + +void KCategorizedView::Private::layoutChanged(bool forceItemReload) +{ + if (proxyModel && categoryDrawer && proxyModel->isCategorizedModel() && + ((forceItemReload || + (modelSortRole != proxyModel->sortRole()) || + (modelSortColumn != proxyModel->sortColumn()) || + (modelSortOrder != proxyModel->sortOrder()) || + (modelLastRowCount != proxyModel->rowCount()) || + (modelCategorized != proxyModel->isCategorizedModel())))) + { + // Force the view to update all elements + listView->rowsInsertedArtifficial(QModelIndex(), 0, proxyModel->rowCount() - 1); + + if (!forceItemReload) + { + modelSortRole = proxyModel->sortRole(); + modelSortColumn = proxyModel->sortColumn(); + modelSortOrder = proxyModel->sortOrder(); + modelLastRowCount = proxyModel->rowCount(); + modelCategorized = proxyModel->isCategorizedModel(); + } + } + else if (proxyModel && categoryDrawer && proxyModel->isCategorizedModel()) + { + updateScrollbars(); + } +} + +void KCategorizedView::Private::drawDraggedItems() +{ + QRect rectToUpdate; + QRect currentRect; + foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes()) + { + int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset(); + int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset(); + + currentRect = visualRect(index); + currentRect.adjust(dx, dy, dx, dy); + + if (currentRect.intersects(listView->viewport()->rect())) + { + rectToUpdate = rectToUpdate.united(currentRect); + } + } + + listView->viewport()->update(lastDraggedItemsRect.united(rectToUpdate)); + + lastDraggedItemsRect = rectToUpdate; +} + + +//============================================================================== + + +KCategorizedView::KCategorizedView(QWidget *parent) + : QListView(parent) + , d(new Private(this)) +{ +} + +KCategorizedView::~KCategorizedView() +{ + delete d; +} + +void KCategorizedView::setGridSize(const QSize &size) +{ + QListView::setGridSize(size); + + d->layoutChanged(true); +} + +void KCategorizedView::setModel(QAbstractItemModel *model) +{ + d->lastSelection = QItemSelection(); + d->forcedSelectionPosition = 0; + d->elementsInfo.clear(); + d->elementsPosition.clear(); + d->categoriesIndexes.clear(); + d->categoriesPosition.clear(); + d->categories.clear(); + d->intersectedIndexes.clear(); + d->modelIndexList.clear(); + d->hovered = QModelIndex(); + d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; + + if (d->proxyModel) + { + QObject::disconnect(d->proxyModel, + SIGNAL(layoutChanged()), + this, SLOT(slotLayoutChanged())); + + QObject::disconnect(d->proxyModel, + SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(slotLayoutChanged())); + + QObject::disconnect(d->proxyModel, + SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); + } + + QListView::setModel(model); + + d->proxyModel = dynamic_cast<KCategorizedSortFilterProxyModel*>(model); + + if (d->proxyModel) + { + d->modelSortRole = d->proxyModel->sortRole(); + d->modelSortColumn = d->proxyModel->sortColumn(); + d->modelSortOrder = d->proxyModel->sortOrder(); + d->modelLastRowCount = d->proxyModel->rowCount(); + d->modelCategorized = d->proxyModel->isCategorizedModel(); + + QObject::connect(d->proxyModel, + SIGNAL(layoutChanged()), + this, SLOT(slotLayoutChanged())); + + QObject::connect(d->proxyModel, + SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(slotLayoutChanged())); + + QObject::connect(d->proxyModel, + SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); + + if (d->proxyModel->rowCount()) + { + d->layoutChanged(true); + } + } + else + { + d->modelCategorized = false; + } +} + +QRect KCategorizedView::visualRect(const QModelIndex &index) const +{ + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + return QListView::visualRect(index); + } + + if (!qobject_cast<const QSortFilterProxyModel*>(index.model())) + { + return d->visualRect(d->proxyModel->mapFromSource(index)); + } + + return d->visualRect(index); +} + +KCategoryDrawer *KCategorizedView::categoryDrawer() const +{ + return d->categoryDrawer; +} + +void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer) +{ + d->lastSelection = QItemSelection(); + d->forcedSelectionPosition = 0; + d->elementsInfo.clear(); + d->elementsPosition.clear(); + d->categoriesIndexes.clear(); + d->categoriesPosition.clear(); + d->categories.clear(); + d->intersectedIndexes.clear(); + d->modelIndexList.clear(); + d->hovered = QModelIndex(); + d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; + + if (!categoryDrawer && d->proxyModel) + { + QObject::disconnect(d->proxyModel, + SIGNAL(layoutChanged()), + this, SLOT(slotLayoutChanged())); + + QObject::disconnect(d->proxyModel, + SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(slotLayoutChanged())); + + QObject::disconnect(d->proxyModel, + SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); + } + else if (categoryDrawer && d->proxyModel) + { + QObject::connect(d->proxyModel, + SIGNAL(layoutChanged()), + this, SLOT(slotLayoutChanged())); + + QObject::connect(d->proxyModel, + SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(slotLayoutChanged())); + + QObject::connect(d->proxyModel, + SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); + } + + d->categoryDrawer = categoryDrawer; + + if (categoryDrawer) + { + if (d->proxyModel) + { + if (d->proxyModel->rowCount()) + { + d->layoutChanged(true); + } + } + } + else + { + updateGeometries(); + } +} + +QModelIndex KCategorizedView::indexAt(const QPoint &point) const +{ + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + return QListView::indexAt(point); + } + + QModelIndex index; + + QModelIndexList item = d->intersectionSet(QRect(point, point)); + + if (item.count() == 1) + { + index = item[0]; + } + + return index; +} + +void KCategorizedView::reset() +{ + QListView::reset(); + + d->lastSelection = QItemSelection(); + d->forcedSelectionPosition = 0; + d->elementsInfo.clear(); + d->elementsPosition.clear(); + d->categoriesIndexes.clear(); + d->categoriesPosition.clear(); + d->categories.clear(); + d->intersectedIndexes.clear(); + d->modelIndexList.clear(); + d->hovered = QModelIndex(); + d->biggestItemSize = QSize(0, 0); + d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; +} + +void KCategorizedView::paintEvent(QPaintEvent *event) +{ + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + QListView::paintEvent(event); + return; + } + + QStyleOptionViewItemV3 option = viewOptions(); + option.widget = this; + if (wordWrap()) + { + option.features |= QStyleOptionViewItemV2::WrapText; + } + + QPainter painter(viewport()); + QRect area = event->rect(); + const bool focus = (hasFocus() || viewport()->hasFocus()) && + currentIndex().isValid(); + const QStyle::State state = option.state; + const bool enabled = (state & QStyle::State_Enabled) != 0; + + painter.save(); + + QModelIndexList dirtyIndexes = d->intersectionSet(area); + foreach (const QModelIndex &index, dirtyIndexes) + { + option.state = state; + option.rect = visualRect(index); + + if (selectionModel() && selectionModel()->isSelected(index)) + { + option.state |= QStyle::State_Selected; + } + + if (enabled) + { + QPalette::ColorGroup cg; + if ((d->proxyModel->flags(index) & Qt::ItemIsEnabled) == 0) + { + option.state &= ~QStyle::State_Enabled; + cg = QPalette::Disabled; + } + else + { + cg = QPalette::Normal; + } + option.palette.setCurrentColorGroup(cg); + } + + if (focus && currentIndex() == index) + { + option.state |= QStyle::State_HasFocus; + if (this->state() == EditingState) + option.state |= QStyle::State_Editing; + } + + // we are only interested to give the mouse over feedback when no + // dragging is happening (ereslibre) + if ((index == d->hovered) && !d->mouseButtonPressed && + (this->state() == QAbstractItemView::NoState)) + option.state |= QStyle::State_MouseOver; + else + option.state &= ~QStyle::State_MouseOver; + + itemDelegate(index)->paint(&painter, option, index); + } + + // Redraw categories + QStyleOptionViewItem otherOption; + bool intersectedInThePast = false; + foreach (const QString &category, d->categories) + { + otherOption = option; + otherOption.rect = d->categoryVisualRect(category); + otherOption.state &= ~QStyle::State_MouseOver; + + if (otherOption.rect.intersects(area)) + { + intersectedInThePast = true; + + QModelIndex indexToDraw = d->proxyModel->index(d->categoriesIndexes[category][0].row(), d->proxyModel->sortColumn()); + + d->drawNewCategory(indexToDraw, + d->proxyModel->sortRole(), otherOption, &painter); + } + else if (intersectedInThePast) + { + break; // the visible area has been finished, we don't need to keep asking, the rest won't intersect + // this is doable because we know that categories are correctly ordered on the list + } + } + + if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection)) + { + if (d->mouseButtonPressed && !d->isDragging) + { + QPoint start, end, initialPressPosition; + + initialPressPosition = d->initialPressPosition; + + initialPressPosition.setY(initialPressPosition.y() - verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() - horizontalOffset()); + + if (d->initialPressPosition.x() > d->mousePosition.x() || + d->initialPressPosition.y() > d->mousePosition.y()) + { + start = d->mousePosition; + end = initialPressPosition; + } + else + { + start = initialPressPosition; + end = d->mousePosition; + } + + QStyleOptionRubberBand yetAnotherOption; + yetAnotherOption.initFrom(this); + yetAnotherOption.shape = QRubberBand::Rectangle; + yetAnotherOption.opaque = false; + yetAnotherOption.rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16)); + painter.save(); + style()->drawControl(QStyle::CE_RubberBand, &yetAnotherOption, &painter); + painter.restore(); + } + } + + if (d->isDragging && !d->dragLeftViewport) + { + painter.setOpacity(0.5); + d->drawDraggedItems(&painter); + } + + painter.restore(); +} + +void KCategorizedView::resizeEvent(QResizeEvent *event) +{ + QListView::resizeEvent(event); + + // Clear the items positions cache + d->elementsPosition.clear(); + d->categoriesPosition.clear(); + d->forcedSelectionPosition = 0; + + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + return; + } + + d->updateScrollbars(); +} + +void KCategorizedView::setSelection(const QRect &rect, + QItemSelectionModel::SelectionFlags flags) +{ + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + QListView::setSelection(rect, flags); + return; + } + + if (!flags) + return; + + if (flags & QItemSelectionModel::Clear) + { + selectionModel()->clear(); + d->lastSelection.clear(); + } + + QModelIndexList dirtyIndexes = d->intersectionSet(rect); + + // no items affected, just leave + if (!dirtyIndexes.count()) + { + selectionModel()->select(d->lastSelection, QItemSelectionModel::SelectCurrent); + + return; + } + + QModelIndex topLeft; + QModelIndex bottomRight; + + if (d->mouseButtonPressed || d->rightMouseButtonPressed) // selection with click + drag + { + QItemSelection selection; + + QModelIndex prev = dirtyIndexes[0]; + QModelIndex first = prev; + foreach (const QModelIndex &index, dirtyIndexes) + { + // we have a different interval. non-contiguous items + if ((index.row() - prev.row()) > 1) { + selection << QItemSelectionRange(first, prev); + + first = index; + } + + prev = index; + } + + selection << QItemSelectionRange(first, prev); + + if (flags & QItemSelectionModel::Current) + { + if (rect.topLeft() == rect.bottomRight()) + { + selectionModel()->setCurrentIndex(indexAt(rect.topLeft()), QItemSelectionModel::NoUpdate); + } + + selection.merge(d->lastSelection, flags); + } + else + { + selection.merge(selectionModel()->selection(), flags); + + selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); + + return; + } + + selectionModel()->select(selection, flags); + } + else // selection with click + keyboard keys + { + QModelIndex topLeftIndex = indexAt(QPoint(rect.topLeft().x(), + rect.topLeft().y())); + QModelIndex bottomRightIndex = indexAt(QPoint(rect.bottomRight().x(), + rect.bottomRight().y())); + + // keyboard selection comes "upside down". Let's normalize it + if (topLeftIndex.row() > bottomRightIndex.row()) + { + QModelIndex auxIndex = topLeftIndex; + topLeftIndex = bottomRightIndex; + bottomRightIndex = auxIndex; + } + + int viewportWidth = viewport()->width() - spacing(); + int itemWidth; + + if (gridSize().isEmpty()) + { + itemWidth = d->biggestItemSize.width(); + } + else + { + itemWidth = gridSize().width(); + } + + int itemWidthPlusSeparation = spacing() + itemWidth; + if (!itemWidthPlusSeparation) + itemWidthPlusSeparation++; + int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + if (!elementsPerRow) + elementsPerRow++; + + QModelIndexList theoricDirty(dirtyIndexes); + dirtyIndexes.clear(); + int first = model()->rowCount(); + int last = 0; + + foreach (const QModelIndex &index, theoricDirty) + { + if ((index.row() < first) && + ((((topLeftIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) && + ((topLeftIndex.row() % elementsPerRow) <= (index.row() % elementsPerRow))) || + (topLeftIndex.row() / elementsPerRow) != (index.row() / elementsPerRow))) + { + first = index.row(); + topLeft = index; + } + + if ((index.row() > last) && + ((((bottomRightIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) && + ((bottomRightIndex.row() % elementsPerRow) >= (index.row() % elementsPerRow))) || + (bottomRightIndex.row() / elementsPerRow) != (index.row() / elementsPerRow))) + { + last = index.row(); + bottomRight = index; + } + } + + for (int i = first; i <= last; i++) + { + dirtyIndexes << model()->index(i, theoricDirty[0].column(), theoricDirty[0].parent()); + } + + QItemSelection selection(topLeft, bottomRight); + + selectionModel()->select(selection, flags); + } +} + +void KCategorizedView::mouseMoveEvent(QMouseEvent *event) +{ + QListView::mouseMoveEvent(event); + + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + return; + } + + QModelIndexList item = d->intersectionSet(QRect(event->pos(), event->pos())); + + if (item.count() == 1) + { + d->hovered = item[0]; + } + else + { + d->hovered = QModelIndex(); + } + + const QString previousHoveredCategory = d->hoveredCategory; + + d->mousePosition = event->pos(); + d->hoveredCategory = QString(); + + // Redraw categories + foreach (const QString &category, d->categories) + { + if (d->categoryVisualRect(category).intersects(QRect(event->pos(), event->pos()))) + { + d->hoveredCategory = category; + viewport()->update(d->categoryVisualRect(category)); + } + else if ((category == previousHoveredCategory) && + (!d->categoryVisualRect(previousHoveredCategory).intersects(QRect(event->pos(), event->pos())))) + { + viewport()->update(d->categoryVisualRect(category)); + } + } + + QRect rect; + if (d->mouseButtonPressed && !d->isDragging) + { + QPoint start, end, initialPressPosition; + + initialPressPosition = d->initialPressPosition; + + initialPressPosition.setY(initialPressPosition.y() - verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() - horizontalOffset()); + + if (d->initialPressPosition.x() > d->mousePosition.x() || + d->initialPressPosition.y() > d->mousePosition.y()) + { + start = d->mousePosition; + end = initialPressPosition; + } + else + { + start = initialPressPosition; + end = d->mousePosition; + } + + rect = QRect(start, end).adjusted(-16, -16, 16, 16); + rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect()); + + viewport()->update(rect); + } +} + +void KCategorizedView::mousePressEvent(QMouseEvent *event) +{ + d->dragLeftViewport = false; + + if (event->button() == Qt::LeftButton) + { + d->mouseButtonPressed = true; + + d->initialPressPosition = event->pos(); + d->initialPressPosition.setY(d->initialPressPosition.y() + + verticalOffset()); + d->initialPressPosition.setX(d->initialPressPosition.x() + + horizontalOffset()); + } + else if (event->button() == Qt::RightButton) + { + d->rightMouseButtonPressed = true; + } + + QListView::mousePressEvent(event); + + d->lastSelection = selectionModel()->selection(); + + viewport()->update(d->categoryVisualRect(d->hoveredCategory)); +} + +void KCategorizedView::mouseReleaseEvent(QMouseEvent *event) +{ + d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; + + QListView::mouseReleaseEvent(event); + + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + return; + } + + QPoint initialPressPosition = viewport()->mapFromGlobal(QCursor::pos()); + initialPressPosition.setY(initialPressPosition.y() + verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() + horizontalOffset()); + + if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection) && + (initialPressPosition == d->initialPressPosition)) + { + foreach(const QString &category, d->categories) + { + if (d->categoryVisualRect(category).contains(event->pos())) + { + QItemSelection selection = selectionModel()->selection(); + QModelIndexList indexList = d->categoriesIndexes[category]; + + foreach (const QModelIndex &index, indexList) + { + QModelIndex selectIndex = index.model()->index(index.row(), 0); + + selection << QItemSelectionRange(selectIndex); + } + + selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); + + break; + } + } + } + + QRect rect; + if (!d->isDragging) + { + QPoint start, end, initialPressPosition; + + initialPressPosition = d->initialPressPosition; + + initialPressPosition.setY(initialPressPosition.y() - verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() - horizontalOffset()); + + if (d->initialPressPosition.x() > d->mousePosition.x() || + d->initialPressPosition.y() > d->mousePosition.y()) + { + start = d->mousePosition; + end = initialPressPosition; + } + else + { + start = initialPressPosition; + end = d->mousePosition; + } + + rect = QRect(start, end).adjusted(-16, -16, 16, 16); + rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect()); + + viewport()->update(rect); + } + + if (d->hovered.isValid()) + viewport()->update(visualRect(d->hovered)); + else if (!d->hoveredCategory.isEmpty()) + viewport()->update(d->categoryVisualRect(d->hoveredCategory)); +} + +void KCategorizedView::leaveEvent(QEvent *event) +{ + d->hovered = QModelIndex(); + d->hoveredCategory = QString(); + + QListView::leaveEvent(event); +} + +void KCategorizedView::startDrag(Qt::DropActions supportedActions) +{ + // FIXME: QAbstractItemView does far better here since it sets the + // pixmap of selected icons to the dragging cursor, but it sets a non + // ARGB window so it is no transparent. Use QAbstractItemView when + // this is fixed on Qt. + // QAbstractItemView::startDrag(supportedActions); +#if !defined(DOLPHIN_DRAGANDDROP) + QListView::startDrag(supportedActions); +#endif + + d->isDragging = false; + d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; + + viewport()->update(d->lastDraggedItemsRect); +} + +void KCategorizedView::dragMoveEvent(QDragMoveEvent *event) +{ + d->mousePosition = event->pos(); + + if (d->mouseButtonPressed) + { + d->isDragging = true; + } + else + { + d->isDragging = false; + } + + d->dragLeftViewport = false; + +#if defined(DOLPHIN_DRAGANDDROP) + QAbstractItemView::dragMoveEvent(event); +#else + QListView::dragMoveEvent(event); +#endif + + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + return; + } + + d->drawDraggedItems(); +} + +void KCategorizedView::dragLeaveEvent(QDragLeaveEvent *event) +{ + d->dragLeftViewport = true; + +#if defined(DOLPHIN_DRAGANDDROP) + QAbstractItemView::dragLeaveEvent(event); +#else + QListView::dragLeaveEvent(event); +#endif +} + +void KCategorizedView::dropEvent(QDropEvent *event) +{ +#if defined(DOLPHIN_DRAGANDDROP) + QAbstractItemView::dropEvent(event); +#else + QListView::dropEvent(event); +#endif +} + +QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction, + Qt::KeyboardModifiers modifiers) +{ + if ((viewMode() != KCategorizedView::IconMode) || + !d->proxyModel || + !d->categoryDrawer || + d->categories.isEmpty() || + !d->proxyModel->isCategorizedModel()) + { + return QListView::moveCursor(cursorAction, modifiers); + } + + int viewportWidth = viewport()->width() - spacing(); + int itemWidth; + + if (gridSize().isEmpty()) + { + itemWidth = d->biggestItemSize.width(); + } + else + { + itemWidth = gridSize().width(); + } + + int itemWidthPlusSeparation = spacing() + itemWidth; + if (!itemWidthPlusSeparation) + itemWidthPlusSeparation++; + int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + if (!elementsPerRow) + elementsPerRow++; + + QModelIndex current = selectionModel()->currentIndex(); + + if (!current.isValid()) + { + if (cursorAction == MoveEnd) + { + current = model()->index(model()->rowCount() - 1, 0, QModelIndex()); + d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow; + } + else + { + current = model()->index(0, 0, QModelIndex()); + d->forcedSelectionPosition = 0; + } + + return current; + } + else if (!current.isValid()) + { + return QModelIndex(); + } + + QString lastCategory = d->categories.first(); + QString theCategory = d->categories.first(); + QString afterCategory = d->categories.first(); + + bool hasToBreak = false; + foreach (const QString &category, d->categories) + { + if (hasToBreak) + { + afterCategory = category; + + break; + } + + if (category == d->elementsInfo[current.row()].category) + { + theCategory = category; + + hasToBreak = true; + } + + if (!hasToBreak) + { + lastCategory = category; + } + } + + switch (cursorAction) + { + case QAbstractItemView::MoveUp: { + if (d->elementsInfo[current.row()].relativeOffsetToCategory >= elementsPerRow) + { + int indexToMove = current.row(); + indexToMove -= qMin(((d->elementsInfo[current.row()].relativeOffsetToCategory) + d->forcedSelectionPosition), elementsPerRow - d->forcedSelectionPosition + (d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow)); + + return d->proxyModel->index(indexToMove, 0); + } + else + { + int lastCategoryLastRow = (d->categoriesIndexes[lastCategory].count() - 1) % elementsPerRow; + int indexToMove = current.row() - d->elementsInfo[current.row()].relativeOffsetToCategory; + + if (d->forcedSelectionPosition >= lastCategoryLastRow) + { + indexToMove -= 1; + } + else + { + indexToMove -= qMin((lastCategoryLastRow - d->forcedSelectionPosition + 1), d->forcedSelectionPosition + elementsPerRow + 1); + } + + return d->proxyModel->index(indexToMove, 0); + } + } + + case QAbstractItemView::MoveDown: { + if (d->elementsInfo[current.row()].relativeOffsetToCategory < (d->categoriesIndexes[theCategory].count() - 1 - ((d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow))) + { + int indexToMove = current.row(); + indexToMove += qMin(elementsPerRow, d->categoriesIndexes[theCategory].count() - 1 - d->elementsInfo[current.row()].relativeOffsetToCategory); + + return d->proxyModel->index(indexToMove, 0); + } + else + { + int afterCategoryLastRow = qMin(elementsPerRow, d->categoriesIndexes[afterCategory].count()); + int indexToMove = current.row() + (d->categoriesIndexes[theCategory].count() - d->elementsInfo[current.row()].relativeOffsetToCategory); + + if (d->forcedSelectionPosition >= afterCategoryLastRow) + { + indexToMove += afterCategoryLastRow - 1; + } + else + { + indexToMove += qMin(d->forcedSelectionPosition, elementsPerRow); + } + + return d->proxyModel->index(indexToMove, 0); + } + } + + case QAbstractItemView::MoveLeft: + if (layoutDirection() == Qt::RightToLeft) + { + if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow)) + return current; + + d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow; + +#if 0 //follow qt view behavior. lateral movements won't change visual row + if (d->forcedSelectionPosition < 0) + d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow; +#endif + + return d->proxyModel->index(current.row() + 1, 0); + } + + if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow)) + return current; + + d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow; + +#if 0 //follow qt view behavior. lateral movements won't change visual row + if (d->forcedSelectionPosition < 0) + d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow; +#endif + + return d->proxyModel->index(current.row() - 1, 0); + + case QAbstractItemView::MoveRight: + if (layoutDirection() == Qt::RightToLeft) + { + if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow)) + return current; + + d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow; + +#if 0 //follow qt view behavior. lateral movements won't change visual row + if (d->forcedSelectionPosition < 0) + d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow; +#endif + + return d->proxyModel->index(current.row() - 1, 0); + } + + if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow)) + return current; + + d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow; + +#if 0 //follow qt view behavior. lateral movements won't change visual row + if (d->forcedSelectionPosition < 0) + d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow; +#endif + + return d->proxyModel->index(current.row() + 1, 0); + + default: + break; + } + + return QListView::moveCursor(cursorAction, modifiers); +} + +void KCategorizedView::rowsInserted(const QModelIndex &parent, + int start, + int end) +{ + QListView::rowsInserted(parent, start, end); + + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + d->forcedSelectionPosition = 0; + d->elementsInfo.clear(); + d->elementsPosition.clear(); + d->categoriesIndexes.clear(); + d->categoriesPosition.clear(); + d->categories.clear(); + d->intersectedIndexes.clear(); + d->modelIndexList.clear(); + d->hovered = QModelIndex(); + d->biggestItemSize = QSize(0, 0); + d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; + + return; + } + + rowsInsertedArtifficial(parent, start, end); +} + +void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent, + int start, + int end) +{ + Q_UNUSED(parent); + + d->forcedSelectionPosition = 0; + d->elementsInfo.clear(); + d->elementsPosition.clear(); + d->categoriesIndexes.clear(); + d->categoriesPosition.clear(); + d->categories.clear(); + d->intersectedIndexes.clear(); + d->modelIndexList.clear(); + d->hovered = QModelIndex(); + d->biggestItemSize = QSize(0, 0); + d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; + + if (start > end || end < 0 || start < 0 || !d->proxyModel->rowCount()) + { + return; + } + + // Add all elements mapped to the source model and explore categories + QString prevCategory = d->proxyModel->data(d->proxyModel->index(0, d->proxyModel->sortColumn()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + QString lastCategory = prevCategory; + QModelIndexList modelIndexList; + struct Private::ElementInfo elementInfo; + int offset = -1; + for (int k = 0; k < d->proxyModel->rowCount(); ++k) + { + QModelIndex index = d->proxyModel->index(k, d->proxyModel->sortColumn()); + QModelIndex indexSize = d->proxyModel->index(k, 0); + + d->biggestItemSize = QSize(qMax(sizeHintForIndex(indexSize).width(), + d->biggestItemSize.width()), + qMax(sizeHintForIndex(indexSize).height(), + d->biggestItemSize.height())); + + d->modelIndexList << index; + + lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + + elementInfo.category = lastCategory; + + if (prevCategory != lastCategory) + { + offset = 0; + d->categoriesIndexes.insert(prevCategory, modelIndexList); + d->categories << prevCategory; + modelIndexList.clear(); + } + else + { + offset++; + } + + elementInfo.relativeOffsetToCategory = offset; + + modelIndexList << index; + prevCategory = lastCategory; + + d->elementsInfo.insert(index.row(), elementInfo); + } + + d->categoriesIndexes.insert(prevCategory, modelIndexList); + d->categories << prevCategory; + + d->updateScrollbars(); + + // FIXME: We need to safely save the last selection. This is on my TODO + // list (ereslibre). + selectionModel()->clear(); +} + +void KCategorizedView::rowsRemoved(const QModelIndex &parent, + int start, + int end) +{ + if (d->proxyModel && d->categoryDrawer && d->proxyModel->isCategorizedModel()) + { + // Force the view to update all elements + rowsInsertedArtifficial(QModelIndex(), 0, d->proxyModel->rowCount() - 1); + } +} + +void KCategorizedView::updateGeometries() +{ + if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) + { + QListView::updateGeometries(); + return; + } + + // Avoid QListView::updateGeometries(), since it will try to set another + // range to our scroll bars, what we don't want (ereslibre) + QAbstractItemView::updateGeometries(); +} + +void KCategorizedView::slotLayoutChanged() +{ + d->layoutChanged(); +} + +void KCategorizedView::currentChanged(const QModelIndex ¤t, + const QModelIndex &previous) +{ + // We need to update the forcedSelectionPosition property in order to correctly + // navigate after with keyboard using up & down keys + + int viewportWidth = viewport()->width() - spacing(); + + int itemHeight; + int itemWidth; + + if (gridSize().isEmpty()) + { + itemHeight = d->biggestItemSize.height(); + itemWidth = d->biggestItemSize.width(); + } + else + { + itemHeight = gridSize().height(); + itemWidth = gridSize().width(); + } + + int itemWidthPlusSeparation = spacing() + itemWidth; + if (!itemWidthPlusSeparation) + itemWidthPlusSeparation++; + int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + if (!elementsPerRow) + elementsPerRow++; + + if (d->mouseButtonPressed || d->rightMouseButtonPressed) + d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow; + + QListView::currentChanged(current, previous); +} + +#include "kcategorizedview.moc" Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,119 @@ +/** + * This file is part of the KDE project + * 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 KCATEGORIZEDVIEW_H +#define KCATEGORIZEDVIEW_H + +#include <QtGui/QListView> + +//#include <kdeui_export.h> + +class KCategoryDrawer; + +/** + * @short Item view for listing items + * + * KCategorizedView allows you to use it as it were a QListView. You can add an + * itemCategorizer to it, so your items became categorized depending on the + * KItemCategorizer inherited class rules. + * + * @see KItemCategorizer, KSortFilterProxyModel + * + * @author Rafael Fernández López <ereslibre@kde.org> + */ +class KCategorizedView + : public QListView +{ + Q_OBJECT + +public: + KCategorizedView(QWidget *parent = 0); + + ~KCategorizedView(); + + virtual void setModel(QAbstractItemModel *model); + + void setGridSize(const QSize &size); + + virtual QRect visualRect(const QModelIndex &index) const; + + KCategoryDrawer *categoryDrawer() const; + + void setCategoryDrawer(KCategoryDrawer *categoryDrawer); + + virtual QModelIndex indexAt(const QPoint &point) const; + +public Q_SLOTS: + virtual void reset(); + +protected: + virtual void paintEvent(QPaintEvent *event); + + virtual void resizeEvent(QResizeEvent *event); + + virtual void setSelection(const QRect &rect, + QItemSelectionModel::SelectionFlags flags); + + virtual void mouseMoveEvent(QMouseEvent *event); + + virtual void mousePressEvent(QMouseEvent *event); + + virtual void mouseReleaseEvent(QMouseEvent *event); + + virtual void leaveEvent(QEvent *event); + + virtual void startDrag(Qt::DropActions supportedActions); + + virtual void dragMoveEvent(QDragMoveEvent *event); + + virtual void dragLeaveEvent(QDragLeaveEvent *event); + + virtual void dropEvent(QDropEvent *event); + + virtual QModelIndex moveCursor(CursorAction cursorAction, + Qt::KeyboardModifiers modifiers); + +protected Q_SLOTS: + virtual void rowsInserted(const QModelIndex &parent, + int start, + int end); + + virtual void rowsInsertedArtifficial(const QModelIndex &parent, + int start, + int end); + + virtual void rowsRemoved(const QModelIndex &parent, + int start, + int end); + + virtual void updateGeometries(); + + virtual void slotLayoutChanged(); + + virtual void currentChanged(const QModelIndex ¤t, + const QModelIndex &previous); + + +private: + class Private; + Private *d; +}; + +#endif // KCATEGORIZEDVIEW_H Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview_p.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview_p.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview_p.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorizedview_p.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,164 @@ +/** + * This file is part of the KDE project + * 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 KCATEGORIZEDVIEW_P_H +#define KCATEGORIZEDVIEW_P_H + +class KCategorizedSortFilterProxyModel; +class KCategoryDrawer; + +/** + * @internal + */ +class KCategorizedView::Private +{ +public: + Private(KCategorizedView *listView); + ~Private(); + + + // Methods + + /** + * Returns the list of items that intersects with @p rect + */ + const QModelIndexList &intersectionSet(const QRect &rect); + + /** + * Gets the item rect in the viewport for @p index + */ + QRect visualRectInViewport(const QModelIndex &index) const; + + /** + * Returns the category rect in the viewport for @p category + */ + QRect visualCategoryRectInViewport(const QString &category) const; + + /** + * Caches and returns the rect that corresponds to @p index + */ + const QRect &cacheIndex(const QModelIndex &index); + + /** + * Caches and returns the rect that corresponds to @p category + */ + const QRect &cacheCategory(const QString &category); + + /** + * Returns the rect that corresponds to @p index + * @note If the rect is not cached, it becomes cached + */ + const QRect &cachedRectIndex(const QModelIndex &index); + + /** + * Returns the rect that corresponds to @p category + * @note If the rect is not cached, it becomes cached + */ + const QRect &cachedRectCategory(const QString &category); + + /** + * Returns the visual rect (taking in count x and y offsets) for @p index + * @note If the rect is not cached, it becomes cached + */ + QRect visualRect(const QModelIndex &index); + + /** + * Returns the visual rect (taking in count x and y offsets) for @p category + * @note If the rect is not cached, it becomes cached + */ + QRect categoryVisualRect(const QString &category); + + /** + * This method will draw a new category represented by index + * @param index on the rect specified by @p option.rect, with + * painter @p painter + */ + void drawNewCategory(const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter); + + /** + * This method will update scrollbars ranges. Called when our model changes + * or when the view is resized + */ + void updateScrollbars(); + + /** + * This method will draw dragged items in the painting operation + */ + void drawDraggedItems(QPainter *painter); + + /** + * This method will determine which rect needs to be updated because of a + * dragging operation + */ + void drawDraggedItems(); + + void layoutChanged(bool forceItemReload = false); + + + // Attributes + + struct ElementInfo + { + QString category; + int relativeOffsetToCategory; + }; + + // Basic data + KCategorizedView *listView; + KCategoryDrawer *categoryDrawer; + QSize biggestItemSize; + + // Behavior data + bool mouseButtonPressed; + bool rightMouseButtonPressed; + bool isDragging; + bool dragLeftViewport; + QModelIndex hovered; + QString hoveredCategory; + QPoint initialPressPosition; + QPoint mousePosition; + int forcedSelectionPosition; + + // Cache data + // We cannot merge some of them into structs because it would affect + // performance + QHash<int, struct ElementInfo> elementsInfo; + QHash<int, QRect> elementsPosition; + QHash<QString, QModelIndexList> categoriesIndexes; + QHash<QString, QRect> categoriesPosition; + QStringList categories; + QModelIndexList intersectedIndexes; + QRect lastDraggedItemsRect; + int modelSortRole; + int modelSortColumn; + int modelLastRowCount; + bool modelCategorized; + Qt::SortOrder modelSortOrder; + QItemSelection lastSelection; + + // Attributes for speed reasons + KCategorizedSortFilterProxyModel *proxyModel; + QModelIndexList modelIndexList; +}; + +#endif // KCATEGORIZEDVIEW_P_H Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,118 @@ +/** + * This file is part of the KDE project + * 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 "kcategorydrawer.h" + +#include <QPainter> +#include <QStyleOption> + +//#include <kiconloader.h> +#include "kcategorizedsortfilterproxymodel.h" + +KCategoryDrawer::KCategoryDrawer() +{ +} + +KCategoryDrawer::~KCategoryDrawer() +{ +} + +void KCategoryDrawer::drawCategory(const QModelIndex &index, + int /*sortRole*/, + const QStyleOption &option, + QPainter *painter) const +{ + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + + QColor color; + + if (option.state & QStyle::State_Selected) + { + color = option.palette.color(QPalette::HighlightedText); + } + else + { + color = option.palette.color(QPalette::Text); + } + + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + + if (option.state & QStyle::State_Selected) + { + QColor selected = option.palette.color(QPalette::Highlight); + + QLinearGradient gradient(option.rect.topLeft(), + option.rect.bottomRight()); + gradient.setColorAt(option.direction == Qt::LeftToRight ? 0 + : 1, selected); + gradient.setColorAt(option.direction == Qt::LeftToRight ? 1 + : 0, Qt::transparent); + + painter->fillRect(option.rect, gradient); + } + else if (option.state & QStyle::State_MouseOver) + { + QColor hover = option.palette.color(QPalette::Highlight).light(); + hover.setAlpha(88); + + QLinearGradient gradient(option.rect.topLeft(), + option.rect.bottomRight()); + gradient.setColorAt(option.direction == Qt::LeftToRight ? 0 + : 1, hover); + gradient.setColorAt(option.direction == Qt::LeftToRight ? 1 + : 0, Qt::transparent); + + painter->fillRect(option.rect, gradient); + } + + QFont painterFont = painter->font(); + painterFont.setWeight(QFont::Bold); + QFontMetrics metrics(painterFont); + painter->setFont(painterFont); + + QRect lineRect(option.rect.left(), + option.rect.bottom() - 1, + option.rect.width(), + 1); + + QLinearGradient gradient(option.rect.topLeft(), + option.rect.bottomRight()); + gradient.setColorAt(option.direction == Qt::LeftToRight ? 0 + : 1, color); + gradient.setColorAt(option.direction == Qt::LeftToRight ? 1 + : 0, Qt::transparent); + + painter->fillRect(lineRect, gradient); + + painter->setPen(color); + + painter->drawText(option.rect, Qt::AlignVCenter | Qt::AlignLeft, + metrics.elidedText(category, Qt::ElideRight, option.rect.width())); + + painter->restore(); +} + +int KCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &option) const +{ + Q_UNUSED(index); + + return option.fontMetrics.height() + 4 /* 3 separator; 1 gradient */; +} Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcategorydrawer.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,52 @@ +/** + * This file is part of the KDE project + * 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 KCATEGORYDRAWER_H +#define KCATEGORYDRAWER_H + +//#include <kdeui_export.h> + +class QPainter; +class QModelIndex; +class QStyleOption; + +class KCategoryDrawer +{ +public: + KCategoryDrawer(); + + virtual ~KCategoryDrawer(); + + /** + * This method purpose is to draw a category represented by the given + * @param index with the given @param sortRole sorting role + * + * @note This method will be called one time per category, always with the + * first element in that category + */ + virtual void drawCategory(const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter) const; + + virtual int categoryHeight(const QModelIndex &index, const QStyleOption &option) const; +}; + +#endif // KCATEGORYDRAWER_H Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,219 @@ +/* This file is part of the KDE project + Copyright 2007 Will Stephenson <wstephenson@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) 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 14 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "kcmodulemodel.h" + +#include <QHash> +#include <QList> + +#include "kcategorizedsortfilterproxymodel.h" +#include "menuitem.h" + +Q_DECLARE_METATYPE(MenuItem *) + +SystemSettingsProxyModel::SystemSettingsProxyModel( QObject * parent ) + : KCategorizedSortFilterProxyModel( parent ) +{ + +} + +SystemSettingsProxyModel::~SystemSettingsProxyModel() +{} + +bool SystemSettingsProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const +{ + QVariant leftWeight = left.data( KCModuleModel::WeightRole ); + QVariant rightWeight = right.data( KCModuleModel::WeightRole ); + + if ( !( leftWeight.isValid() && rightWeight.isValid() ) ) { + return KCategorizedSortFilterProxyModel::subSortLessThan( left, right ); + } else { + if ( leftWeight.toInt() == rightWeight.toInt() ) { + return left.data().toString() < right.data().toString(); + } else { + return leftWeight.toInt() < rightWeight.toInt(); + } + } +} + + +bool SystemSettingsProxyModel::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const +{ + QModelIndex index = sourceModel()->index( source_row, 0, source_parent ); + MenuItem * mItem = index.data( Qt::UserRole ).value<MenuItem*>(); + // accept only systemsettings categories that have children +// if ( mItem->children.isEmpty() && mItem->service->serviceTypes().contains("SystemSettingsCategory" ) ) { +// return false; +// } else { +// return KCategorizedSortFilterProxyModel::filterAcceptsRow( source_row, source_parent ); +// } +} + +/*int weightOfService( const KService::Ptr service ) +{ + QVariant tmp = service->property( "X-KDE-Weight", QVariant::Int ); + int weight = tmp.isValid() ? tmp.toInt() : 100; + return weight; +} +*/ +class KCModuleModelPrivate { +public: + KCModuleModelPrivate(){ + } + + MenuItem * rootItem; +}; + +const int KCModuleModel::UserFilterRole = 0x015D1AE6; +const int KCModuleModel::WeightRole = 0x03A8CC00; + +KCModuleModel::KCModuleModel( MenuItem * menuRoot, QObject * parent ) + : QAbstractItemModel( parent ), d( new KCModuleModelPrivate ) +{ + d->rootItem = menuRoot; +} + +KCModuleModel::~KCModuleModel() +{ +} + +int KCModuleModel::rowCount( const QModelIndex & index ) const +{ + int count = 0; + MenuItem * mi; + if ( index.isValid() ) { + mi = static_cast<MenuItem *>( index.internalPointer() ); + } else { + mi = d->rootItem; + } + if ( mi ) { + foreach ( MenuItem * i, mi->children ) { + count += i->children.count(); + } + } + return count; +} + +int KCModuleModel::columnCount( const QModelIndex & /*index*/ ) const +{ + return 2; // name and comment +} + +QModelIndex KCModuleModel::index( int row, int column, const QModelIndex & parent ) const +{ + if ( !hasIndex( row, column, parent ) ) { + return QModelIndex(); + } + MenuItem * parentItem; + if ( !parent.isValid() ) { + parentItem = d->rootItem; + } else { + parentItem = static_cast<MenuItem*>( parent.internalPointer() ); + } + MenuItem * foundItem = parentItem->grandChildAt( row ); + if ( foundItem ) { + QModelIndex index = createIndex( row, column, (void*)foundItem ); + return index; + } + return QModelIndex(); +} + + +QModelIndex KCModuleModel::parent( const QModelIndex & index ) const +{ + if ( !index.isValid() ) { + return QModelIndex(); + } + + MenuItem * parentItem = static_cast<MenuItem*>( index.internalPointer() )->parent; + if ( parentItem == d->rootItem ) { + return QModelIndex(); + } else { + return createIndex( parentItem->parent->children.indexOf( parentItem ), 0, parentItem ); + } +} + +QVariant KCModuleModel::data(const QModelIndex &index, int role) const +{ + MenuItem * mi = 0; + QVariant theData; + if ( !index.isValid() ) { + return QVariant(); + } + mi = static_cast<MenuItem *>( index.internalPointer() ); +// QStringList searchKeyWords; + switch ( role ) { + case Qt::DisplayRole: + switch ( index.column() ) { + case 0: +// theData.setValue( mi->service->name()); + + break; + case 1: + // theData.setValue( mi->service->comment()); + break; + default: + break; + } + break; + case Qt::DecorationRole: + if ( index.column() == 0 ) + // theData = QVariant( KIcon( mi->service->icon() ) ); + break; + case KCategorizedSortFilterProxyModel::CategorySortRole: + if ( mi->parent ) +// theData.setValue( QString("%1%2").arg( QString::number( weightOfService( mi->parent->service) ), 5, '0' ).arg( mi->parent->service->name() ) ); + break; + case KCategorizedSortFilterProxyModel::CategoryDisplayRole: + if ( mi->parent ) +// theData.setValue( mi->parent->service->name()); + break; + case Qt::UserRole: + theData.setValue( mi ); + break; + case UserFilterRole: + foreach ( MenuItem * child, mi->children ) { +// searchKeyWords << child->item.keywords() << child->service->name(); + } +// searchKeyWords << mi->item.keywords() << mi->service->name(); +// theData.setValue( searchKeyWords.join( QString() ) ); + break; + case WeightRole: +// theData.setValue( weightOfService( mi->service ) ); + break; + default: + break; + } + return theData; +} + +Qt::ItemFlags KCModuleModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +QVariant KCModuleModel::headerData(int section, Qt::Orientation orientation, int role ) const +{ + return QAbstractItemModel::headerData( section, orientation, role ); +} + Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kcmodulemodel.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,66 @@ +/* This file is part of the KDE project + Copyright 2007 Will Stephenson <wstephenson@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) 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 14 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ +#ifndef KCMODULEMODEL_H +#define KCMODULEMODEL_H + +#include <QAbstractItemModel> +#include "kcategorizedsortfilterproxymodel.h" + +class MenuItem; +class KCModuleModelPrivate; + +class SystemSettingsProxyModel : public KCategorizedSortFilterProxyModel +{ +public: + SystemSettingsProxyModel(QObject *parent = 0); + virtual ~SystemSettingsProxyModel(); + virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; + virtual bool filterAcceptsRow( int source_column, const QModelIndex & source_parent ) const; +}; + +class KCModuleModel : public QAbstractItemModel +{ +Q_OBJECT +public: + static const int UserFilterRole, WeightRole; + KCModuleModel( MenuItem * menuRoot, QObject * parent = 0 ); + ~KCModuleModel(); + // setup method + // QAbstractItemModel reimplementations + QModelIndex index( int row, int column, const QModelIndex & parent = QModelIndex() ) const; + QModelIndex parent( const QModelIndex & index ) const; + int rowCount( const QModelIndex & index ) const; + int columnCount( const QModelIndex & index ) const; + + QVariant data(const QModelIndex &index, int role) const; + + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; +private: + KCModuleModelPrivate * d; +}; + +class KCModuleSortFilterProxyModel : public KCategorizedSortFilterProxyModel +{ +public: +protected: +}; + +#endif Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,134 @@ +/* + kicongrouppage.cpp + + Copyright (c) 2007 Michael D. Stemle, Jr. <manchicken@notsosoft.net> + + 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 <QtAlgorithms> +#include <QStyle> + +#include "kicongrouppage.h" + +/*********** KIconGroupPage **************/ +KIconGroupPage::KIconGroupPage(QWidget* parent) : QFrame(parent) { + render(); +} + +KIconGroupPage::~KIconGroupPage() { + // Delete the rows... + qDeleteAll(m_rows.values().begin(), m_rows.values().end()); + m_rows.clear(); +} + +const KIconGroupRow* KIconGroupPage::appendGroup(QString name) { + KIconGroupRow* group = new KIconGroupRow(name, parentWidget()); + + m_rows.insert(name, group); + + render(); + + return group; +} + +const KIconGroupItem* KIconGroupPage::appendIconToGroup(const QString& group, + const QIcon& icon, + const QString& label) { + if (!m_rows.contains(group)) { + appendGroup(group); + } + + return m_rows[group]->appendIcon(icon, label); +} + +void KIconGroupPage::render() { + m_layout = new QBoxLayout(QBoxLayout::TopToBottom, parentWidget()); +} + + +/*********** KIconGroupRow **************/ +KIconGroupRow::KIconGroupRow(QWidget* parent) : QBoxLayout(QBoxLayout::LeftToRight, parent) { + render(); +} + +KIconGroupRow::KIconGroupRow(QString& name, QWidget* parent) : QBoxLayout(QBoxLayout::LeftToRight, parent) { + setGroupName(name); + render(); +} + +KIconGroupRow::~KIconGroupRow() { + // Let's delete our icons + qDeleteAll(m_icons.begin(), m_icons.end()); + m_icons.clear(); +} + +const KIconGroupItem* KIconGroupRow::appendIcon( const QIcon& icon, const QString& label ) { + KIconGroupItem* item = new KIconGroupItem(parentWidget(),icon,label); + item->setParent(parentWidget()); + + m_icons.append(item); + + return item; +} + +void KIconGroupRow::render() { +} + + +/*********** KIconGroupItem **************/ +KIconGroupItem::KIconGroupItem(QWidget* parent, + const QIcon& icon, + const QString& label) : QLabel(parent) { + m_parent = parent; + m_icon = icon; + m_text = label; // Lets keep our own copy... + + render(); +} + +void KIconGroupItem::render() { + QStyle *stl = 0; + + // If there's no parent, we've got no style, can't draw an icon. + if (!m_parent) { + return; + } + + setPixmap(static_cast<const QPixmap&>(m_icon.pixmap(m_parent->style()->pixelMetric(QStyle::PM_IconViewIconSize)))); + setText(m_text); +} + +void KIconGroupItem::setParent(QWidget* parent) { + m_parent = parent; + + render(); +} + +void KIconGroupItem::setIcon(const QIcon& icon) { + m_icon = icon; + + render(); +} + +void KIconGroupItem::setLabel(const QString& label) { + m_text = label; + + render(); +} + +#include "kicongrouppage.moc" Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/kicongrouppage.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,258 @@ +/* + kicongrouppage.h + + Copyright (c) 2007 Michael D. Stemle, Jr. <manchicken@notsosoft.net> + + 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 KICONGROUPPAGE_H + +#define KICONGROUPPAGE_H + +#include <QObject> +#include <QList> +#include <QMap> +#include <QBoxLayout> +#include <QIcon> +#include <QLabel> +#include <kicon.h> + +class KIconGroupPage; +class KIconGroupRow; +class KIconGroupItem; + +/* DESIGN + VBox contains two rows: title and HBOX (maybe a third for a line? + HBOX contains columns of VBOXes + Those VBoxes contain two rows: icon and title + + +---------------Box-----------------+ + | | + | +-------------Box---------------+ | + | | | | + | | +-----------Box-------------+ | | + | | | | | | + | | | +--QLabel--+ +--QLabel--+ | | | + | | | | | | | | | | + | | | | ICON | | ICON | | | | + | | | | LABEL | | LABEL | | | | + | | | | | | | | | | + | | | +----------+ +----------+ | | | + | | | | | | + | | +---------------------------+ | | + | | | | + | +-------------------------------+ | + | | + +-----------------------------------+ + + + */ + + +/** + * A page of group icons + **/ +class KIconGroupPage : public QFrame { + Q_OBJECT; + + /** + * Property for the page name + **/ + Q_PROPERTY(QString m_pageName READ pageName WRITE setPageName); + + public: + + /** + * Constructor for KIconGroupPage + * + * @param parent The parent widget for the page.. + **/ + explicit KIconGroupPage(QWidget* parent = 0); + + ~KIconGroupPage(); + + /** + * Append a group to the page + * + * @param title The title of the group + * @returns A constant pointer to the group that was added. + **/ + void appendGroup(QString name); + + /** + * Append an icon to a group + * + * @param group The group name to append the icon to + * @param icon The icon to use + * @param label The label to use with the icon + * @returns A constant pointer to the item that was added. + **/ + const KIconGroupItem* appendIconToGroup(const QString& name, + const QIcon& icon, + const QString& label); + + /** + * Set the page name + * + * @param name The name to assign. + **/ + void setPageName(QString name) { m_pageName = name; }; + + /** + * Get the page name + * + * @return Returns the page name + **/ + QString pageName() const { return m_pageName; }; + + private: + void render(); + + // Internal values + QString m_pageName; + QMap<QString, KIconGroupRow*> m_rows; + QBoxLayout* m_layout; +}; + + +/** + * The row of icon groups + **/ +class KIconGroupRow : public QBoxLayout { + Q_OBJECT; + + /** + * Property for the icon group name + **/ + Q_PROPERTY(QString m_groupName READ groupName WRITE setGroupName); + + public: + + /** + * Constructor for KIconGroupRow + * + * @param parent The parent to stick the KIconGroupRow widget into. + **/ + explicit KIconGroupRow(QWidget* parent = 0); + + /** + * Constructor for KIconGroupRow + * + * @param parent The parent to stick the KIconGroupRow widget into. + * @param name The name for the icon group row. + **/ + explicit KIconGroupRow(QString& name, QWidget* parent = 0); + + /** + * Deconstructor + **/ + ~KIconGroupRow(); + + /** + * Append an icon + * + * @param icon The icon to add + * @param label The label to add + * @returns A constant pointer to the item that was just added. + **/ + const KIconGroupItem* appendIcon( const QIcon& icon, const QString& label ); + + /** + * Set the group name + * + * @param name The name to assign + **/ + void setGroupName(QString name) { m_groupName = name; }; + + /** + * Get the group name + * + * @return The group name. + **/ + QString groupName() const { return m_groupName; }; + + private: + void render(); + + QString m_groupName; + QList<KIconGroupItem*> m_icons; +}; + + +/** + * KIconGroupItem + * + * @notes This is the low-level icon class for the icon groups. + **/ +class KIconGroupItem : public QLabel { + Q_OBJECT; + + public: + + /** + * A single icon in the group. + * @param parent The parent widget + * @param icon The icon to display + * @param label The label to display for the icon. + **/ + explicit KIconGroupItem(QWidget* parent, const QIcon& icon, const QString& label); + + /** + * Set the parent widget + * + * @param parent The parent widget to set + **/ + void setParent(QWidget* parent); + + /** + * Set the icon + * + * @param icon The icon to add to the group item + **/ + void setIcon(const QIcon& icon); + + /** + * Get the icon + * + * @return Returns the currently set icon object + **/ + const QIcon& icon() { return m_icon; }; + + /** + * Set the label + * + * @param label The label to set + **/ + void setLabel(const QString& label); + + /** + * Fetch the label + **/ + const QString& label() { return m_text; }; + + protected: + void render(); + + private: + Q_DISABLE_COPY(KIconGroupItem); + QWidget* m_parent; + QIcon m_icon; + QString m_text; +}; + +#endif // KICONGROUPPAGE_H Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/main.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/main.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/main.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/main.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,15 @@ +#include <QApplication> + +#include "main_window.h" + + +int main(int argc, char **argv) +{ +QApplication app(argc, argv); + +MainWindow mainWin; + +mainWin.show(); +return app.exec(); + +} Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,67 @@ +#include "main_window.h" + +#include <QLayout> +#include <QLabel> + + + +#include "kcategorizedview.h" +#include "menuitem.h" +#include "kcmodulemodel.h" +#include "kcategorydrawer.h" + +MainWindow::MainWindow() : QMainWindow() +{ + + + QWidget *centralWidget = new QWidget; + setCentralWidget(centralWidget); + + QHBoxLayout *layout = new QHBoxLayout; + centralWidget->setLayout(layout); + + +// KCategorizedView *view = new KCategorizedView(this); + +// layout->addWidget(view); + + + MenuItem *rootItem = new MenuItem(true, 0); + MenuItem *first = new MenuItem(false, rootItem); + + first->name="hi"; + first->caption="hallo"; + + + +// foreach ( MenuItem* item, rootItem->children ) { + KCModuleModel *model = new KCModuleModel( first, this ); + KCategoryDrawer * drawer = new KCategoryDrawer; + KCategorizedView * tv = new KCategorizedView( this ); + tv->setSelectionMode(QAbstractItemView::SingleSelection); +// tv->setSpacing(KDialog::spacingHint()); + tv->setCategoryDrawer( drawer ); + tv->setViewMode( QListView::IconMode ); +// tv->setItemDelegate( new ModuleIconItemDelegate( this ) ); + tv->setMouseTracking( true ); + tv->viewport()->setAttribute( Qt::WA_Hover ); + KCategorizedSortFilterProxyModel * kcsfpm = new SystemSettingsProxyModel( this ); + kcsfpm->setCategorizedModel( true ); + kcsfpm->setSourceModel( model ); + kcsfpm->setFilterRole( KCModuleModel::UserFilterRole ); + kcsfpm->setFilterCaseSensitivity( Qt::CaseInsensitive ); + kcsfpm->sort( 0 ); + tv->setModel( kcsfpm ); + + + +} + + +MainWindow::~MainWindow() +{ +} + + + +#include "main_window.moc" Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/main_window.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,20 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> + +class MainWindow : public QMainWindow +{ +Q_OBJECT + +public: + MainWindow(); + ~MainWindow(); + +public slots: + +private: + +}; + +#endif Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + Copyright 2007 Will Stephenson <wstephenson@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) 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 14 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "menuitem.h" + +MenuItem::MenuItem( bool isMenu, MenuItem * itsParent ) + : parent( itsParent ), + menu( isMenu ), + name( QString() ), + caption( QString() ) + +{ + if ( parent ) { + parent->children.append( this ); + } +} + +MenuItem::~MenuItem() +{ + qDeleteAll( children ); +} + +MenuItem * MenuItem::grandChildAt( int index ) +{ + int count = 0; + MenuItem * foundItem = 0; + foreach ( MenuItem * child, children ) { + foreach ( MenuItem * grandChild, child->children ) { + if ( count == index ) { + foundItem = grandChild; + break; + } + count++; + } + if ( foundItem ) { + break; + } + } + return foundItem; +} + Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/menuitem.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + Copyright 2007 Will Stephenson <wstephenson@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) 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 14 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ +#ifndef KCMENUITEM_H +#define KCMENUITEM_H + +#include <QList> +#include <QString> + +/** + * A menu consists of menu items. An item is either another menu or a module. + */ +class MenuItem { +public: + MenuItem( bool isMenu, MenuItem * parent ); + ~MenuItem(); + MenuItem * grandChildAt( int index ); + MenuItem * parent; + QList< MenuItem * > children; + bool menu; + QString name; + QString caption; +}; + +#endif Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,133 @@ +/** + * This file is part of the System Settings package + * Copyright (C) 2005 Benjamin C Meyer +* <ben+systempreferences at meyerhome dot net> + * + * 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 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 "moduleiconitem.h" +#include <kiconloader.h> +#include <kdebug.h> +#include <kcmoduleinfo.h> + +#include <climits> + +#include <qapplication.h> +#include <qpainter.h> + +#define IMAGE_SIZE 32 +#define ICON_WIDTH 100 + +ModuleIconItemDelegate::ModuleIconItemDelegate(QObject *parent) : QItemDelegate(parent) +{ +} + +void ModuleIconItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + painter->save(); + painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); + + QStyle *style; + bool selected = option.state & QStyle::State_Selected || option.state & QStyle::State_HasFocus; + if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option)) { + style = v3->widget->style(); + if (!v3->widget->hasFocus()) selected = false; + } else { + style = QApplication::style(); + } + + if (selected) { + painter->fillPath(roundedRectangle(option.rect, 10), option.palette.brush(QPalette::Highlight)); + painter->setPen(option.palette.color(QPalette::HighlightedText)); + } + + if (!selected && (option.state & QStyle::State_MouseOver)) { + QColor hover = option.palette.color(QPalette::Highlight); + hover.setAlpha(88); + painter->fillPath(roundedRectangle(option.rect, 10), hover); + } + + if( index.data( Qt::UserRole ).toInt() == KIconLoader::DisabledState ) { + painter->setPen( option.palette.color( QPalette::Disabled, QPalette::Text ) ); + } + + const QSize &decorationSize = option.decorationSize; + QIcon::Mode iconMode = QIcon::Normal; + if (selected) iconMode = QIcon::Selected; + const QPixmap &pixmap = qvariant_cast<QIcon>(index.data(Qt::DecorationRole)).pixmap(option.decorationSize, iconMode); + int iconX = option.rect.left() + (option.rect.width() - decorationSize.width()) / 2; + painter->drawPixmap(iconX, option.rect.top() + style->pixelMetric(QStyle::PM_FocusFrameVMargin), decorationSize.width(), decorationSize.height(), pixmap); + + QRect textRectangle = option.rect; + textRectangle.setTop(textRectangle.top() + decorationSize.height() + style->pixelMetric(QStyle::PM_FocusFrameVMargin)); + painter->drawText(textRectangle, Qt::AlignHCenter | Qt::TextWordWrap, index.data(Qt::DisplayRole).toString()); + painter->restore(); +} + +// Method taken from KFileItemDelegate. Check whether it has been moved to +// kdefx/kdrawutil.cpp as the comment says on Fredrik's code. If so, remove +// this code (duplication), and use the library one. +QPainterPath ModuleIconItemDelegate::roundedRectangle(const QRectF &rect, qreal radius) const +{ + QPainterPath path(QPointF(rect.left(), rect.top() + radius)); + path.quadTo(rect.left(), rect.top(), rect.left() + radius, rect.top()); // Top left corner + path.lineTo(rect.right() - radius, rect.top()); // Top side + path.quadTo(rect.right(), rect.top(), rect.right(), rect.top() + radius); // Top right corner + path.lineTo(rect.right(), rect.bottom() - radius); // Right side + path.quadTo(rect.right(), rect.bottom(), rect.right() - radius, rect.bottom()); // Bottom right corner + path.lineTo(rect.left() + radius, rect.bottom()); // Bottom side + path.quadTo(rect.left(), rect.bottom(), rect.left(), rect.bottom() - radius); // Bottom left corner + path.closeSubpath(); + + return path; +} + +ModuleIconItem::ModuleIconItem( QListWidget* parent, const KCModuleInfo& module) + : QListWidgetItem(SmallIcon( module.icon(), IMAGE_SIZE ), module.moduleName(), parent), + imageName(module.icon()) +{ + setData( Qt::UserRole, KIconLoader::DefaultState ); + modules.append(module); + setSize(); +} + +ModuleIconItem::ModuleIconItem( QListWidget* parent, const QString &text, + const QString &_imageName ) + : QListWidgetItem( SmallIcon( _imageName, IMAGE_SIZE ), text, parent ), + imageName(_imageName) +{ + setData( Qt::UserRole, KIconLoader::DefaultState ); + setSize(); +} + +void ModuleIconItem::loadIcon( bool enabled ) +{ + int newState = enabled ? KIconLoader::DefaultState : KIconLoader::DisabledState; + if( newState == data( Qt::UserRole ).toInt() ) + return; + + setData( Qt::UserRole, newState ); + setIcon( DesktopIcon( imageName, IMAGE_SIZE , newState ) ); +} + +void ModuleIconItem::setSize() +{ + QStyle *style = listWidget()->style(); + QFontMetrics fm(font()); + const QRect &rect = fm.boundingRect(0, 0, ICON_WIDTH, INT_MAX, Qt::TextWordWrap, text()); + setData(Qt::SizeHintRole, QSize(ICON_WIDTH, IMAGE_SIZE + style->pixelMetric(QStyle::PM_FocusFrameVMargin) + rect.height())); +} Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/moduleiconitem.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,74 @@ +/** + * This file is part of the System Settings package + * Copyright (C) 2005 Benjamin C Meyer + * <ben+systempreferences at meyerhome dot net> + * + * 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 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 MODULEICONITEM_H +#define MODULEICONITEM_H + +#include <QItemDelegate> +#include <QListWidgetItem> +#include <QList> +#include <QPainterPath> +#include <QRectF> + +class KCModuleInfo; + +class ModuleIconItemDelegate : public QItemDelegate +{ + public: + ModuleIconItemDelegate(QObject *parent); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + + private: + // Method taken from KFileItemDelegate. Check whether it has been moved to + // kdefx/kdrawutil.cpp as the comment says on Fredrik's code. If so, remove + // this code (duplication), and use the library one. + QPainterPath roundedRectangle(const QRectF &rect, qreal radius) const; +}; + +/** + * Stores information about what modules goes with this item. + * Also provides means of loading the enabled/disabled image (see kcmsearch). + */ +class ModuleIconItem : public QListWidgetItem +{ + +public: + ModuleIconItem( QListWidget *parent, const KCModuleInfo& module ); + + ModuleIconItem( QListWidget *parent, const QString &text, const QString &imageName ); + + /** + * Update the icon to either be enabled or not. + */ + void loadIcon( bool enabled = true ); + + // The modules that go with this item + QList<KCModuleInfo> modules; + +private: + void setSize(); + + QString imageName; +}; + +#endif // MODULEICONITEM_H + Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.cpp URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.cpp?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.cpp (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.cpp Thu Jan 31 11:10:23 2008 @@ -0,0 +1,189 @@ +/** + * This file is part of the System Settings package + * Copyright (C) 2005 Benjamin C Meyer (ben+systempreferences at meyerhome dot net) + * + * 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 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 "modulesview.h" + +#include <qlabel.h> +#include <QListWidget> +#include <qlayout.h> +#include <kiconloader.h> +#include <kdebug.h> +#include <kservicetypetrader.h> +#include <QApplication> +#include <kdialog.h> + +#include "kcmsearch.h" +#include "moduleiconitem.h" +#include "kcmodulemenu.h" + +ModulesView::ModulesView( KCModuleMenu *rootMenu, const QString &menuPath, QWidget *parent ) : QWidget( parent ), rootMenu( NULL ) +{ + this->rootMenu = rootMenu; + this->menuPath = menuPath; + this->categories = KServiceTypeTrader::self()->query("SystemSettingsCategory"); + + QVBoxLayout *layout = new QVBoxLayout( this ); + layout->setMargin( KDialog::marginHint() ); + layout->setSpacing( KDialog::spacingHint() ); + layout->setObjectName( QLatin1String( "layout" ) ); + + displayName = this->rootMenu->caption; + + QList<MenuItem> subMenus = rootMenu->menuList(menuPath); + QList<MenuItem>::const_iterator it; + for ( it = subMenus.begin(); it != subMenus.end(); ++it ){ + if( !(*it).menu ) + continue; + + // After the first time around add a line + if( it != subMenus.begin() ){ + QFrame *line = new QFrame( this ); + line->setObjectName( QLatin1String( "line" ) ); + line->setFrameShadow( QFrame::Sunken ); + line->setFrameShape( QFrame::HLine ); + layout->addWidget( line ); + } + + // Build the row of modules/icons + createRow( (*it).subMenu, layout ); + } + layout->addStretch(1); + + setBackgroundRole(QPalette::Base); + setForegroundRole(QPalette::Text); + + /* + // Align them up! + uint most = 0; + QList<RowIconView*>::iterator it2; + for ( it2 = groups.begin(); it2 != groups.end(); ++it2 ){ + for (int i = 0; i < (*it2)->count(); ++i ) { + QListWidgetItem * item = (*it2)->item( i ); + if ( item && item->sizeHint().width() > most ) { + most = item->sizeHint().width(); + } + } + } +*/ +/*FIXME + for ( it = groups.begin(); it != groups.end(); ++it ) + (*it)->setGridX(most); + + } +*/ +} + +ModulesView::~ModulesView() +{ +} + +void ModulesView::createRow( const QString &parentPath, QBoxLayout *boxLayout ) +{ + //find the category name and search for it + QString categoryName = parentPath.section('/', -2, -2); + QString iconName; + for (int i = 0; i < categories.size(); ++i) { + const KService* entry = categories.at(i).data(); + if (entry->name() == categoryName) { + iconName = entry->icon(); + break; + } + } + + // Make header + QHBoxLayout *rowLayout = new QHBoxLayout(); + rowLayout->setMargin( 0 ); + rowLayout->setSpacing( 6 ); + rowLayout->setObjectName( QLatin1String( "rowLayout" ) ); + + // Header Icon + QLabel *icon = new QLabel( this ); + icon->setObjectName( QLatin1String( "groupicon" ) ); + icon->setPixmap( SmallIcon( iconName )); + QSizePolicy sp( QSizePolicy::Minimum, QSizePolicy::Preferred ); + sp.setHeightForWidth( icon->sizePolicy().hasHeightForWidth() ); + icon->setSizePolicy( sp ); + rowLayout->addWidget( icon ); + + // Header Name + QLabel *textLabel = new QLabel( this ); + textLabel->setObjectName( QLatin1String( "groupcaption" ) ); + textLabel->setText( categoryName ); + QSizePolicy sp1( QSizePolicy::Expanding, QSizePolicy::Preferred ); + sp1.setHeightForWidth( textLabel->sizePolicy().hasHeightForWidth() ); + textLabel->setSizePolicy( sp1 ); + QFont textLabel_font( textLabel->font() ); + textLabel_font.setBold( true ); + textLabel->setFont( textLabel_font ); + rowLayout->addWidget( textLabel ); + + boxLayout->addLayout( rowLayout ); + + // Make IconView + RowIconView* iconWidget = new RowIconView( this ); + connect(iconWidget, SIGNAL( itemClicked( QListWidgetItem* ) ), + this, SIGNAL( itemSelected( QListWidgetItem* ) ) ); + connect(iconWidget, SIGNAL( itemActivated( QListWidgetItem* ) ), + this, SIGNAL( itemSelected( QListWidgetItem* ) ) ); + groups.append( iconWidget ); + boxLayout->addWidget( iconWidget ); + + int height = 0; + // Add all the items in their proper order + QList<MenuItem> list = rootMenu->menuList( parentPath ); + QList<MenuItem>::const_iterator it; + for ( it = list.begin(); it != list.end(); ++it ){ + ModuleIconItem *item = NULL; + if( !(*it).menu ) { + item = new ModuleIconItem( iconWidget, (*it).item ); + } else { + QString path = (*it).subMenu; + + QString categoryCaption = (*it).caption; + QString iconFile; + for (int i = 0; i < categories.size(); ++i) { + const KService* entry = categories.at(i).data(); + if (entry->name() == categoryCaption) { + iconFile = entry->icon(); + break; + } + } + + const QList<KCModuleInfo> &modules = rootMenu->modules( path ); + if ( modules.count() > 0 ) { + item = new ModuleIconItem( iconWidget, categoryCaption, iconFile); + item->modules = modules; + } + } + if (item) height = qMax(height, item->data(Qt::SizeHintRole).toSize().height()); + } + + // give the proper height to make all the items visible + iconWidget->setMinimumHeight(height); +} + +void ModulesView::clearSelection() { + QList<RowIconView*>::const_iterator it; + for ( it = groups.begin(); it != groups.end(); ++it ) { + (*it)->clearSelection(); + } +} + +#include "modulesview.moc" Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.h URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.h?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.h (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/modulesview.h Thu Jan 31 11:10:23 2008 @@ -0,0 +1,112 @@ +/** + * This file is part of the System Preferences package + * Copyright (C) 2005 Benjamin C Meyer (ben+systempreferences at meyerhome dot net) + * + * 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 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 MODULESVIEW_H +#define MODULESVIEW_H + +#include "moduleiconitem.h" + +#include <QListWidget> +#include <QList> + +#include <KService> +/** + * Overloaded to give a larger default size that fits with text of two lines. + */ +class RowIconView : public QListWidget +{ + +public: + RowIconView( QWidget* parent ) : QListWidget( parent ) + { + setResizeMode(Adjust); + setViewMode(IconMode); + setMovement(Static); + setFrameShape(NoFrame); + setWordWrap(true); + setItemDelegate(new ModuleIconItemDelegate(this)); + } + + // Figure out the hight/width to have only one row + QSize minimumSizeHint() const { + int width = 0; + /* + for ( QIconViewItem *item = firstItem(); item; item = item->nextItem() ) + width += item->width(); + width += spacing()*(count())+(margin()+frameWidth()+lineWidth()+midLineWidth())*2 ; + */ + + //width = count()*gridX()+frameWidth()*2; + width = count()*gridSize().width()+frameWidth()*2; + + int height =48; +//FIXME for ( Q3IconViewItem *item = firstItem(); item; item = item->nextItem() ) +// if(item->height() > height) +// height = item->height(); + // I honestly don't know where the 4+4 is coming from... + // What other spacing did I miss? + height += (/*margin()+*/frameWidth()+spacing()+lineWidth()+midLineWidth())*2+8; + +/* + int h = fontMetrics().height(); + if ( h < 10 ) + h = 10; + int f = 2 * frameWidth(); + int height = ( 2*h ) + f + spacing() * 2 + 32 + lineWidth()*2 + 10; + */ + return QSize( width, height ); + } +}; + +class QBoxLayout; +class KCModuleMenu; + +/** + * This widget contains the IconView's of all of the modules etc + * It is the basic thing that users see. + */ +class ModulesView : public QWidget +{ + // To search the groups + friend class KcmSearch; + +Q_OBJECT +public: + void clearSelection(); + QString displayName; + +signals: + void itemSelected( QListWidgetItem* item ); + +public: + ModulesView( KCModuleMenu *rootMenu, const QString &menuPath, QWidget *parent=0 ); + ~ModulesView(); + +private: + QList<RowIconView*> groups; + KCModuleMenu *rootMenu; + QString menuPath; + KService::List categories; + + void createRow( const QString &parentPath, QBoxLayout *layout ); +}; + +#endif // MODULESVIEW_H + Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettings.desktop URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettings.desktop?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettings.desktop (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettings.desktop Thu Jan 31 11:10:23 2008 @@ -0,0 +1,111 @@ +[Desktop Entry] +Exec=systemsettings -caption "%c" %i +Icon=preferences-system +Type=Application +X-DocPath=systemsettings/index.html +X-KDE-StartupNotify=true + +GenericName=System Settings +GenericName[ar]=إعدادات اÙÙظا٠+GenericName[bg]=СиÑÑемни наÑÑÑойки +GenericName[ca]=Arranjament del sistema +GenericName[csb]=Systemòwé ùstôwë +GenericName[de]=Systemeinstellungen +GenericName[el]=Î¡Ï Î¸Î¼Î¯ÏÎµÎ¹Ï ÏÏ ÏÏήμαÏÎ¿Ï +GenericName[eo]=Sistema agordo +GenericName[es]=Preferencias del sistema +GenericName[et]=Süsteemi seadistused +GenericName[eu]=Sistemaren ezarpenak +GenericName[fi]=Järjestelmän asetukset +GenericName[fr]=Configuration du système +GenericName[fy]=Systeemynstellings +GenericName[ga]=Socruithe an Chórais +GenericName[gl]=Configuración do Sistema +GenericName[hu]=RendszerbeállÃtások +GenericName[is]=Kerfisstillingar +GenericName[it]=Impostazioni di sistema +GenericName[ja]=ã·ã¹ãã è¨å® +GenericName[km]=áá¶áâáááááâááááááááâ +GenericName[ko]=ìì¤í ì¤ì +GenericName[ku]=Mîhengên Pergalê +GenericName[lv]=SistÄmas iestatÄ«jumi +GenericName[nb]=Systeminnstillinger +GenericName[nds]=Systeeminstellen +GenericName[nl]=Systeeminstellingen +GenericName[nn]=Systemoppsett +GenericName[pa]=ਸਿਸà¨à¨® ਸà©à¨à¨¿à©°à¨ +GenericName[pl]=Ustawienia systemowe +GenericName[pt]=Configuração do Sistema +GenericName[pt_BR]=Configurações do Sistema +GenericName[ru]=СиÑÑемнÑе паÑамеÑÑÑ +GenericName[se]=Vuogádatheivehusat +GenericName[sl]=Sistemske nastavitve +GenericName[sr]=СиÑÑемÑке поÑÑавке +GenericName[sr@latin]=Sistemske postavke +GenericName[sv]=Systeminställningar +GenericName[tg]=ТанзимоÑҳои ÑиÑÑема +GenericName[th]=à¸à¸±à¹à¸à¸à¹à¸²à¸£à¸°à¸à¸ +GenericName[tr]=Sistem Ayarları +GenericName[uk]=СиÑÑÐµÐ¼Ð½Ñ Ð¿Ð°ÑамеÑÑи +GenericName[wa]=Apontiaedjes do sistinme +GenericName[x-test]=xxSystem Settingsxx +GenericName[zh_CN]=ç³»ç»è®¾ç½® +GenericName[zh_TW]=系統è¨å® + +Name=System Settings +Name[ar]=إعدادات اÙÙظا٠+Name[be]=СÑÑÑÑмнÑÑ Ð½Ð°ÑÑаÑÐ»ÐµÐ½Ð½Ñ +Name[bg]=СиÑÑемни наÑÑÑойки +Name[br]=Dibarzhoù ar reizhiad +Name[ca]=Arranjament del sistema +Name[csb]=Systemòwé ùstôwë +Name[de]=Systemeinstellungen +Name[el]=Î¡Ï Î¸Î¼Î¯ÏÎµÎ¹Ï ÏÏ ÏÏήμαÏÎ¿Ï +Name[eo]=Sistema agordo +Name[es]=Preferencias del sistema +Name[et]=Süsteemi seadistused +Name[eu]=Sistemaren ezarpenak +Name[fa]=تÙظÛ٠ات سÛست٠+Name[fi]=Järjestelmän asetukset +Name[fr]=Configuration du système +Name[fy]=Systeemynstellings +Name[ga]=Socruithe an Chórais +Name[gl]=Configuración do sistema +Name[he]=×××ר×ת ×ער×ת +Name[hi]=तà¤à¤¤à¥à¤° विनà¥à¤¯à¤¾à¤¸ +Name[hr]=Postavke sustava +Name[hu]=RendszerbeállÃtások +Name[is]=Kerfisstillingar +Name[it]=Impostazioni di sistema +Name[ja]=KDE ã·ã¹ãã è¨å® +Name[kk]=Ðүйе паÑамеÑÑлеÑÑ +Name[km]=áá¶áâáááááâááááááááâ +Name[ko]=ìì¤í ì¤ì +Name[ku]=Mîhengên Pergalê +Name[lv]=SistÄmas iestatÄ«jumi +Name[nb]=Systeminnstillinger +Name[nds]=Systeeminstellen +Name[ne]=पà¥à¤°à¤£à¤¾à¤²à¥ सà¥à¤à¤¿à¤ +Name[nl]=Systeeminstellingen +Name[nn]=Systemoppsett +Name[pa]=ਸਿਸà¨à¨® ਸà©à¨à¨¿à©°à¨ +Name[pl]=Ustawienia systemowe +Name[pt]=Configuração do Sistema +Name[pt_BR]=Configurações do Sistema +Name[ru]=СиÑÑемнÑе паÑамеÑÑÑ +Name[se]=Vuogádatheivehusat +Name[sl]=Sistemske nastavitve +Name[sr]=СиÑÑемÑке поÑÑавке +Name[sr@latin]=Sistemske postavke +Name[sv]=Systeminställningar +Name[tg]=ТанзимоÑҳои ÑиÑÑема +Name[th]=à¸à¸±à¹à¸à¸à¹à¸²à¸£à¸°à¸à¸ +Name[tr]=Sistem Ayarları +Name[uk]=СиÑÑÐµÐ¼Ð½Ñ Ð¿Ð°ÑамеÑÑи +Name[wa]=Apontiaedjes do sistinme +Name[x-test]=xxSystem Settingsxx +Name[zh_CN]=ç³»ç»è®¾ç½® +Name[zh_TW]=系統è¨å® + +X-DBUS-StartupType=Unique +Categories=Qt;KDE;System; Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsrc URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsrc?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsrc (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsrc Thu Jan 31 11:10:23 2008 @@ -0,0 +1,3 @@ +[MainWindow Toolbar mainToolBar] +ToolButtonStyle=TextBesideIcon + Added: branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsui.rc URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsui.rc?rev=44036&view=auto ============================================================================== --- branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsui.rc (added) +++ branches/tmp/tgoettlicher/yast2cc_rewrite/src/systemsettingsui.rc Thu Jan 31 11:10:23 2008 @@ -0,0 +1,32 @@ +<!DOCTYPE kpartgui> +<kpartgui name="systemsettings" version="1"> + +<MenuBar> + <Menu name="file"><Text>&File</Text> + <Action name="resetModule"/> + <Action name="defaultModule"/> + <Separator/> + </Menu> + + <Menu name="view"><Text>&View</Text> + <Action name="showAll"/> + </Menu> + + <Menu name="help"> + <Action name="help_about_module" append="about_merge"/> + </Menu> +</MenuBar> + +<ToolBar name="mainToolBar" iconText="icontextright"> + <Action name="showAll"/> + <Separator/> + <Action name="spacer"/> + <Action name="searchText"/> + <Action name="search"/> +</ToolBar> + +<ActionProperties> + <Action name="showAll" /> +</ActionProperties> + +</kpartgui> -- To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org For additional commands, e-mail: yast-commit+help@opensuse.org
participants (1)
-
tgoettlicher@svn.opensuse.org