Author: tgoettlicher
Date: Mon May 23 15:58:18 2011
New Revision: 64088
URL: http://svn.opensuse.org/viewcvs/yast?rev=64088&view=rev
Log:
backported trunk to sp2
Added:
branches/SuSE-Code-11-SP1-Branch/control-center/src/CMakeLists.txt
branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST-systemsettings.desktop
branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel_p.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview_p.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmodulemodel.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmodulemodel.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/kicongrouppage.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/kicongrouppage.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/listview.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/main_window.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/main_window.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/menuitem.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/menuitem.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/models_test.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/moduleiconitem.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/moduleiconitem.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/yccmoduleinfoprovider.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/yccmoduleinfoprovider.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqdesktopfilesmodel.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqdesktopfilesmodel.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqmodulegroupsmodel.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqmodulegroupsmodel.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqmodulesmodel.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqmodulesmodel.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqmodulesproxymodel.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqmodulesproxymodel.h
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqsavelogs.cpp
branches/SuSE-Code-11-SP1-Branch/control-center/src/yqsavelogs.h
Modified:
branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST.desktop
branches/SuSE-Code-11-SP1-Branch/control-center/src/main.cpp
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/CMakeLists.txt
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/CMakeLists.txt?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/CMakeLists.txt (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/CMakeLists.txt Mon May 23 15:58:18 2011
@@ -0,0 +1,86 @@
+INCLUDE(${QT_USE_FILE})
+
+INCLUDE_DIRECTORIES(/usr/include/initng ${CMAKE_CURRENT_BINARY_DIR})
+
+SET(THEMEDIR "/usr/share/YaST2/theme")
+
+ADD_DEFINITIONS(-DQT_NO_DEBUG_OUTPUT)
+ADD_DEFINITIONS("-DLOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/share/YaST2/locale\"")
+ADD_DEFINITIONS("-DICON_DIR=\"${THEMEDIR}/current/icons/32x32/apps\"")
+ADD_DEFINITIONS("-DFALLBACK_ICON_DIR=\"${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps\"")
+ADD_DEFINITIONS("-DPIXMAP_DIR=\"${THEMEDIR}/current/icons/32x32/apps\"")
+ADD_DEFINITIONS("-DDESKTOP_TRANSLATIONS_DIR=\"${CMAKE_INSTALL_PREFIX}/share/locale\"")
+ADD_DEFINITIONS("-DMODULES_DESKTOP_DIR=\"${CMAKE_INSTALL_PREFIX}/share/applications/YaST2\"")
+ADD_DEFINITIONS("-DGROUPS_DESKTOP_DIR=\"${CMAKE_INSTALL_PREFIX}/share/applications/YaST2/groups\"")
+
+SET(yast2-control-center_SRCS
+ main.cpp
+ main_window.cpp
+ kcategorizedview.cpp
+ kcategorydrawer.cpp
+ kcategorizedsortfilterproxymodel.cpp
+ moduleiconitem.cpp
+ yccmoduleinfoprovider.cpp
+ yqdesktopfilesmodel.cpp
+ yqmodulegroupsmodel.cpp
+ yqmodulesmodel.cpp
+ yqmodulesproxymodel.cpp
+ yqsavelogs.cpp
+ i18n.cpp
+)
+
+#SET(yast2-control-center_UIS
+# main_window.ui
+#)
+
+SET(yast2-control-center_HDRS
+ main_window.h
+ kcategorizedview.h
+ kcategorydrawer.h
+ kcategorizedsortfilterproxymodel.h
+ moduleiconitem.h
+ kcategorizedview_p.h
+ yccmoduleinfoprovider.h
+ yqdesktopfilesmodel.h
+ yqmodulegroupsmodel.h
+ yqmodulesmodel.h
+ yqmodulesproxymodel.h
+ listview.h
+ yqsavelogs.h
+ i18n.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_EXECUTABLE(y2controlcenter ${yast2-control-center_SRCS} ${yast2-control-center_MOC} ${yast2-control-center_RCC_SRCS})
+TARGET_LINK_LIBRARIES(y2controlcenter ${QT_LIBRARIES})
+INSTALL(TARGETS y2controlcenter DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/YaST2/bin)
+
+INSTALL(FILES yast.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps )
+INSTALL(FILES YaST.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications )
+INSTALL(FILES YaST-systemsettings.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/kde4/services )
+
+SET(MODELS_TEST_SRCS
+ models_test.cpp
+ yqdesktopfilesmodel.cpp
+ yqmodulegroupsmodel.cpp
+ yccmoduleinfoprovider.cpp
+ yqmodulesmodel.cpp )
+
+
+QT4_AUTOMOC(${MODELS_TEST_SRCS})
+ADD_EXECUTABLE(models_test ${MODELS_TEST_SRCS})
+TARGET_LINK_LIBRARIES(models_test ${QT_QTCORE_LIBRARIES} ${QT_QTGUI_LIBRARIES})
+
+FIND_PACKAGE(KDE4)
+IF ( KDE4_FOUND )
+ ADD_SUBDIRECTORY(kde)
+ENDIF ( KDE4_FOUND )
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST-systemsettings.desktop
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST-systemsettings.desktop?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST-systemsettings.desktop (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST-systemsettings.desktop Mon May 23 15:58:18 2011
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Type=Service
+Name=YaST
+Icon=yast
+GenericName=Administrator Settings
+Exec=kdesu -c /sbin/yast2
+X-KDE-RootOnly=true
+X-KDE-System-Settings-Parent-Category=system-administration
+X-KDE-ServiceTypes=SystemSettingsExternalApp
Modified: branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST.desktop
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST.desktop?rev=64088&r1=64087&r2=64088&view=diff
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST.desktop (original)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/YaST.desktop Mon May 23 15:58:18 2011
@@ -4,8 +4,5 @@
Name=YaST
Icon=yast
GenericName=Control Center
-Exec=/sbin/yast2
-OnlyShowIn=KDE;GNOME;
-X-KDE-SubstituteUID=true
-X-KDE-RootOnly=true
+Exec=/usr/bin/xdg-su -c /sbin/yast2
Encoding=UTF-8
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.cpp
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.cpp?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.cpp (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.cpp Mon May 23 15:58:18 2011
@@ -0,0 +1,10 @@
+
+#include "i18n.h"
+
+void
+set_textdomain (const char* domain)
+{
+ bindtextdomain (domain, LOCALEDIR);
+ textdomain (domain);
+ bind_textdomain_codeset (domain, "UTF-8");
+}
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.h?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.h (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/i18n.h Mon May 23 15:58:18 2011
@@ -0,0 +1,22 @@
+#ifndef MYINTL_H
+#define MYINTL_H
+
+
+#include
+#include
+
+
+inline QString _(const char* msgid)
+{
+ return QString::fromUtf8 (gettext(msgid));
+}
+
+inline QString _(const char* msgid1, const char* msgid2, unsigned long int n)
+{
+ return QString::fromUtf8 (ngettext (msgid1, msgid2, n));
+}
+
+void set_textdomain (const char* domain);
+
+
+#endif
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.cpp
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.cpp?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.cpp (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.cpp Mon May 23 15:58:18 2011
@@ -0,0 +1,349 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ * Copyright (C) 2007 John Tapsell
+ * Copyright (C) 2006 by Dominic Battre
+ * Copyright (C) 2006 by Martin Pool
+ *
+ * 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 "yqdesktopfilesmodel.h"
+#include "kcategorizedsortfilterproxymodel_p.h"
+
+#include
+#include <iostream>
+
+#include <QItemSelection>
+#include <QStringList>
+#include <QSize>
+#include <QDebug>
+
+KCategorizedSortFilterProxyModel::KCategorizedSortFilterProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+ , d(new Private())
+
+{
+ setFilterCaseSensitivity( Qt::CaseInsensitive );
+}
+
+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
+{
+ QModelIndex i1 = createIndex(left.row(), YQDesktopFilesModel::Name);
+ QModelIndex i2 = createIndex(right.row(), YQDesktopFilesModel::Name);
+
+ QVariant l = (left.model() ? left.model()->data(i1, Qt::UserRole) : QVariant());
+ QVariant r = (right.model() ? right.model()->data(i2, Qt::UserRole) : QVariant());
+
+ return l.toString() < r.toString();
+}
+
+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());
+
+ QVariant s1 = (left.model() ? left.model()->data( left, CategoryDisplayRole ) : QVariant());
+ QVariant s2 = (right.model() ? right.model()->data( right, CategoryDisplayRole ) : QVariant());
+
+ Q_ASSERT(l.isValid());
+ Q_ASSERT(r.isValid());
+ Q_ASSERT(s1.isValid());
+ Q_ASSERT(s2.isValid());
+ Q_ASSERT(l.type() == r.type());
+ Q_ASSERT(s1.type() == s2.type());
+
+ qlonglong lint = l.toLongLong();
+ qlonglong rint = r.toLongLong();
+
+ if (lint < rint)
+ {
+ return -1;
+ }
+
+ if (lint > rint)
+ {
+ return 1;
+ }
+
+ if (lint == rint)
+ {
+
+ QString lstr = s1.toString();
+ QString rstr = s2.toString();
+
+ if (d->sortCategoriesByNaturalComparison)
+ {
+ return naturalCompare(lstr, rstr);
+ }
+ else
+ {
+ if (lstr < rstr)
+ {
+ return -1;
+ }
+
+ if (lstr > rstr)
+ {
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+bool KCategorizedSortFilterProxyModel::filterAcceptsRow( int row, const QModelIndex &srcindex ) const
+{
+ QModelIndex i0 = sourceModel()->index( row, YQDesktopFilesModel::Group, srcindex);
+ QModelIndex i1 = sourceModel()->index( row, 0, srcindex);
+ QStringList keywordList = sourceModel()->data( i1, KeywordsRole ).toStringList();
+ QString keywords = keywordList.join(" ");
+
+ bool nameMatches = QSortFilterProxyModel::filterAcceptsRow( row, srcindex );
+ bool keywordMatches = ( !keywords.isEmpty() && keywords.contains( filterFixedString()) );
+
+ if( nameMatches || keywordMatches )
+ {
+ QString gr = sourceModel()->data(i0, Qt::UserRole).toString();
+ d->filterGroups.insert( gr );
+ }
+
+ return ( nameMatches || keywordMatches );
+}
+
+void KCategorizedSortFilterProxyModel::customFilterFunction( const QString &s )
+{
+ d->filterGroups.clear();
+ setFilterFixedString( s );
+ d->filterString = s;
+ invalidateFilter();
+ invalidate();
+}
+
+QString KCategorizedSortFilterProxyModel::matchingGroupFilterRegexp()
+{
+ QStringList slist = d->filterGroups.toList();
+
+ if ( !slist.isEmpty() )
+ return slist.join("|");
+ else
+ // dumb constant, make sure nothing matches if the list of matching groups is empty
+ return QString("zzzz");
+}
+
+QString KCategorizedSortFilterProxyModel::filterFixedString() const
+{
+ return d->filterString;
+}
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.h?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.h (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel.h Mon May 23 15:58:18 2011
@@ -0,0 +1,195 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ * Copyright (C) 2007 John Tapsell
+ * Copyright (C) 2006 by Dominic Battre
+ * Copyright (C) 2006 by Martin Pool
+ *
+ * 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
+
+//#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
+ */
+//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.
+
+ KeywordsRole = 0x09B2C2AA
+ };
+
+ 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);
+
+ void customFilterFunction( const QString &s );
+
+ QString matchingGroupFilterRegexp();
+
+ QString filterFixedString() const;
+
+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;
+
+ virtual bool filterAcceptsRow( int row, const QModelIndex &index ) const;
+
+private:
+ class Private;
+ Private *const d;
+
+};
+
+
+#endif // KCATEGORIZEDSORTFILTERPROXYMODEL_H
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel_p.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel_p.h?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel_p.h (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedsortfilterproxymodel_p.h Mon May 23 15:58:18 2011
@@ -0,0 +1,53 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ * Copyright (C) 2007 John Tapsell
+ *
+ * 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
+
+#include <QSet>
+
+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;
+
+ QSet<QString> filterGroups;
+ QString filterString;
+};
+
+#endif
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.cpp
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.cpp?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.cpp (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.cpp Mon May 23 15:58:18 2011
@@ -0,0 +1,1552 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kcategorizedview.h"
+#include "kcategorizedview_p.h"
+
+#include // trunc on C99 compliant systems
+
+#include <QPainter>
+#include <QScrollBar>
+#include <QPaintEvent>
+#include <QDebug>
+#include <iostream>
+
+
+#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;
+ const bool leftToRightFlow = (listView->flow() == QListView::LeftToRight);
+
+ if (leftToRightFlow)
+ {
+ 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() && leftToRightFlow)
+ {
+ itemHeight = biggestItemSize.height();
+ itemWidth = biggestItemSize.width();
+ }
+ else if (leftToRightFlow)
+ {
+ itemHeight = listView->gridSize().height();
+ itemWidth = listView->gridSize().width();
+ }
+ else if (listView->gridSize().isEmpty() && !leftToRightFlow)
+ {
+ 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 (leftToRightFlow)
+ {
+ 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
+ {
+ const QSize sizeHint = listView->sizeHintForIndex(heightIndex);
+ if (sizeHint.width() < itemWidth && leftToRightFlow) {
+ retRect.setWidth(sizeHint.width());
+ retRect.moveLeft(retRect.left() + (itemWidth - sizeHint.width()) / 2);
+ }
+ retRect.setHeight(qMin(sizeHint.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 || !categoryDrawer || !proxyModel->isCategorizedModel() || !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);
+ QHash::iterator it = elementsPosition.insert(index.row(), rect);
+
+ return *it;
+}
+
+// We're sure categoriesPosition doesn't contain category
+const QRect &KCategorizedView::Private::cacheCategory(const QString &category)
+{
+ QRect rect = visualCategoryRectInViewport(category);
+ QHash::iterator it = categoriesPosition.insert(category, rect);
+
+ return *it;
+}
+
+const QRect &KCategorizedView::Private::cachedRectIndex(const QModelIndex &index)
+{
+ QHash::const_iterator it = elementsPosition.constFind(index.row());
+ if (it != elementsPosition.constEnd()) // If we have it cached
+ { // return it
+ return *it;
+ }
+ else // Otherwise, cache it
+ { // and return it
+ return cacheIndex(index);
+ }
+}
+
+const QRect &KCategorizedView::Private::cachedRectCategory(const QString &category)
+{
+ QHash::const_iterator it = categoriesPosition.constFind(category);
+ if (it != categoriesPosition.constEnd()) // If we have it cached
+ { // return it
+ return *it;
+ }
+ 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)
+{
+ QStyleOptionViewItemV4 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();
+ }
+ }
+
+ 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(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(rowsRemoved(QModelIndex,int,int)));
+ }
+
+ QListView::setModel(model);
+
+ d->proxyModel = dynamic_cast(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(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(index.model()))
+ {
+ return d->visualRect(d->proxyModel->mapFromSource(index));
+ }
+
+ return d->visualRect(index);
+}
+
+void KCategorizedView::scrollTo (const QModelIndex &index )
+{
+ QRect rect = visualRect( index );
+ int v = verticalScrollBar()->value();
+ int header = categoryDrawer()->categoryHeight(QModelIndex(), viewOptions());
+
+ // upper edge of 1st icon in a group + current position of scrollbar
+ // scroll a bit more up, to show the cat. header, but not too much (over max)
+ int scroll = qMin( rect.top() + v - header, verticalScrollBar()->maximum() );
+ verticalScrollBar()->setValue( scroll );
+}
+
+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(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(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();
+ }
+}
+
+
+
+void KCategorizedView::selectCategory( const QString cat )
+{
+ QRect previous = d->categoryVisualRect( d->selectedCategory );
+ d->selectedCategory = cat;
+ QRect current = d->categoryVisualRect( d->selectedCategory );
+
+ viewport()->update( previous );
+ viewport()->update( current );
+}
+
+QModelIndex KCategorizedView::indexAt(const QPoint &point) const
+{
+ if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
+ {
+ return QListView::indexAt(point);
+ }
+
+ QModelIndex index;
+
+ const 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;
+ }
+
+ bool alternatingRows = alternatingRowColors();
+
+ QStyleOptionViewItemV4 option = viewOptions();
+ option.widget = this;
+ if (wordWrap())
+ {
+ option.features |= QStyleOptionViewItemV4::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);
+ bool alternate = false;
+ if (dirtyIndexes.count())
+ {
+ alternate = dirtyIndexes[0].row() % 2;
+ }
+ foreach (const QModelIndex &index, dirtyIndexes)
+ {
+ if (alternatingRows && alternate)
+ {
+ option.features |= QStyleOptionViewItemV4::Alternate;
+ alternate = false;
+ }
+ else if (alternatingRows)
+ {
+ option.features &= ~QStyleOptionViewItemV4::Alternate;
+ alternate = true;
+ }
+ 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;
+ }
+
+ if (index == d->hovered)
+ option.state |= QStyle::State_MouseOver;
+ else
+ option.state &= ~QStyle::State_MouseOver;
+
+ itemDelegate(index)->paint(&painter, option, index);
+ }
+
+ // Redraw categories
+ QStyleOptionViewItemV4 otherOption;
+ bool intersectedInThePast = false;
+ foreach (const QString &category, d->categories)
+ {
+ otherOption = option;
+ otherOption.rect = d->categoryVisualRect(category);
+ otherOption.state &= ~QStyle::State_MouseOver;
+
+ if (category == d->selectedCategory)
+ otherOption.state |= QStyle::State_Selected;
+ else
+ otherOption.state &= ~QStyle::State_Selected;
+
+ 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::mouseMoveEvent(QMouseEvent *event)
+{
+ QListView::mouseMoveEvent(event);
+
+ if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
+ {
+ return;
+ }
+
+ const 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.clear();
+
+ // 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);
+ }
+ viewport()->update();
+}
+
+void KCategorizedView::mousePressEvent(QMouseEvent *event)
+{
+ d->dragLeftViewport = false;
+
+ QListView::mousePressEvent(event);
+ 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());
+
+ emit leftMouseClick( indexAt( event->pos()));
+ }
+ else if (event->button() == Qt::RightButton)
+ {
+ d->rightMouseButtonPressed = true;
+ }
+
+
+ if (selectionModel())
+ {
+ 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))
+ {
+ selectionModel()->select( d->hovered, QItemSelectionModel::SelectCurrent);
+ }
+
+ 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.clear();
+
+ 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)
+ Q_UNUSED(supportedActions);
+#else
+ 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->hovered = indexAt(event->pos());
+
+#if !defined(DOLPHIN_DRAGANDDROP)
+ d->drawDraggedItems();
+#endif
+}
+
+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() ? selectionModel()->currentIndex()
+ : QModelIndex();
+
+ 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;
+ }
+
+ 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)
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(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);
+}
+
+void KCategorizedView::dataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight)
+{
+ if (topLeft == bottomRight)
+ {
+ d->cacheIndex(topLeft);
+ }
+ else
+ {
+ const int columnStart = topLeft.column();
+ const int columnEnd = bottomRight.column();
+ const int rowStart = topLeft.row();
+ const int rowEnd = bottomRight.row();
+
+ for (int row = rowStart; row <= rowEnd; ++row)
+ {
+ for (int column = columnStart; column <= columnEnd; ++column)
+ {
+ d->cacheIndex(d->proxyModel->index(row, column));
+ }
+ }
+ }
+
+ QListView::dataChanged(topLeft, bottomRight);
+ slotLayoutChanged();
+}
+
+#include "kcategorizedview.moc"
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.h?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.h (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview.h Mon May 23 15:58:18 2011
@@ -0,0 +1,128 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KCATEGORIZEDVIEW_H
+#define KCATEGORIZEDVIEW_H
+
+#include
+
+//#include
+#define KDEUI_EXPORT
+
+class KCategoryDrawer;
+
+/**
+ * @short Item view for listing items
+ *
+ * KCategorizedView allows you to use it as it were a QListView.
+ * Subclass KCategorizedSortFilterProxyModel to provide category information for items.
+ *
+ * @see KCategorizedSortFilterProxyModel
+ *
+ * @author Rafael Fernández López
+ */
+class KDEUI_EXPORT 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;
+
+ void scrollTo (const QModelIndex &index );
+
+ KCategoryDrawer *categoryDrawer() const;
+
+ void setCategoryDrawer(KCategoryDrawer *categoryDrawer);
+
+ void selectCategory ( const QString cat );
+
+ 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);
+
+ virtual void dataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight);
+
+signals:
+ void leftMouseClick( const QModelIndex &idx );
+
+private:
+ class Private;
+ Private *const d;
+};
+
+#endif // KCATEGORIZEDVIEW_H
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview_p.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview_p.h?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview_p.h (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorizedview_p.h Mon May 23 15:58:18 2011
@@ -0,0 +1,165 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#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;
+ QString selectedCategory;
+ QPoint initialPressPosition;
+ QPoint mousePosition;
+ int forcedSelectionPosition;
+
+ // Cache data
+ // We cannot merge some of them into structs because it would affect
+ // performance
+ QHash elementsInfo;
+ QHash elementsPosition;
+ QHash categoriesIndexes;
+ QHash 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/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.cpp
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.cpp?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.cpp (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.cpp Mon May 23 15:58:18 2011
@@ -0,0 +1,114 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kcategorydrawer.h"
+
+#include <QPainter>
+#include <QStyleOption>
+#include <QApplication>
+#include <QDebug>
+
+#define HORIZONTAL_HINT 3
+
+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;
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ if (option.state & QStyle::State_Selected)
+ {
+ color = option.palette.color(QPalette::HighlightedText);
+ QColor bgcolor = option.palette.color(QPalette::Highlight);
+ painter->fillRect(option.rect, linearG( option, bgcolor ));
+ }
+ else
+ {
+ color = option.palette.color(QPalette::Text);
+ }
+
+
+ QStyleOptionViewItemV4 viewOptions;
+ viewOptions.rect = option.rect;
+ viewOptions.palette = option.palette;
+ viewOptions.direction = option.direction;
+ viewOptions.state = option.state;
+ viewOptions.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
+ QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewOptions, painter, 0);
+
+ 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);
+
+
+ painter->fillRect(lineRect, linearG( option, color ));
+
+ painter->setPen(color);
+
+ QRect textRect(option.rect);
+ textRect.setLeft(textRect.left() + HORIZONTAL_HINT);
+ textRect.setRight(textRect.right() - HORIZONTAL_HINT);
+ painter->drawText(textRect, 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 */;
+}
+
+QLinearGradient KCategoryDrawer::linearG ( const QStyleOption &option, const QColor col ) const
+{
+
+ QLinearGradient gradient = QLinearGradient(option.rect.topLeft(),
+ option.rect.bottomRight());
+
+ gradient.setColorAt(option.direction == Qt::LeftToRight ? 0
+ : 1, col);
+ gradient.setColorAt(option.direction == Qt::LeftToRight ? 1
+ : 0, Qt::transparent);
+
+ return gradient;
+}
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.h?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.h (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcategorydrawer.h Mon May 23 15:58:18 2011
@@ -0,0 +1,56 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2007 Rafael Fernández López
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KCATEGORYDRAWER_H
+#define KCATEGORYDRAWER_H
+
+#include "kcategorizedsortfilterproxymodel.h"
+#define KDEUI_EXPORT
+
+class QPainter;
+class QLinearGradient;
+class QModelIndex;
+class QStyleOption;
+
+class KDEUI_EXPORT 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;
+
+ QLinearGradient linearG( const QStyleOption &option, const QColor col ) const;
+};
+
+#endif // KCATEGORYDRAWER_H
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.cpp
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.cpp?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.cpp (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.cpp Mon May 23 15:58:18 2011
@@ -0,0 +1,215 @@
+/*
+ Copyright (c) 1999 Matthias Hoelzer-Kluepfel
+ Copyright (c) 2000 Matthias Elter
+ Copyright (c) 2003 Daniel Molkentin
+ Copyright (c) 2003,2006 Matthias Kretz
+
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kcmoduleinfo.h"
+
+#include
+
+//#include
+//#include
+//#include
+//#include
+//#include
+
+#include <iostream>
+
+class KCModuleInfo::Private
+{
+ public:
+ Private();
+// Private( KService::Ptr );
+
+ QStringList keywords;
+ QString name, icon, lib, handle, fileName, doc, comment;
+ bool allLoaded;
+ int weight;
+
+ //KService::Ptr service;
+
+ /**
+ * Reads the service entries specific for KCModule from the desktop file.
+ * The usual desktop entries are read in the Private ctor.
+ */
+ void loadAll();
+};
+
+//KCModuleInfo::Private::Private()
+//{
+//}
+
+//KCModuleInfo::Private::Private( KService::Ptr s )
+KCModuleInfo::Private::Private( )
+ : allLoaded( false )
+// , service( s )
+{
+// if ( !service )
+// {
+// kDebug(712) << "Could not find the service.";
+// return;
+// }
+
+ // set the modules simple attributes
+/* name = service->name();
+ comment = service->comment();
+ icon = service->icon();
+ fileName = service->entryPath();
+ lib = service->library();
+ keywords = service->keywords(); */
+
+ name = "name";
+ comment = "comment";
+ icon = "icon";
+ fileName = "fileName";
+ lib = "lib";
+ keywords = QStringList("keywords");
+
+
+}
+
+KCModuleInfo::KCModuleInfo()
+{
+ d = new Private;
+}
+
+KCModuleInfo::KCModuleInfo(const QString& desktopFile)
+{
+// d = new Private( KService::serviceByStorageId(desktopFile) );
+ d = new Private( );
+}
+
+//KCModuleInfo::KCModuleInfo( KService::Ptr moduleInfo )
+//{
+// d = new Private( moduleInfo );
+//}
+
+KCModuleInfo::KCModuleInfo( const KCModuleInfo &rhs )
+{
+ d = new Private;
+ ( *this ) = rhs;
+}
+
+KCModuleInfo &KCModuleInfo::operator=( const KCModuleInfo &rhs )
+{
+ *d = *(rhs.d);
+ return *this;
+}
+
+bool KCModuleInfo::operator==( const KCModuleInfo & rhs ) const
+{
+ return ( ( d->name == rhs.d->name ) && ( d->lib == rhs.d->lib ) && ( d->fileName == rhs.d->fileName ) );
+}
+
+bool KCModuleInfo::operator!=( const KCModuleInfo & rhs ) const
+{
+ return ! operator==( rhs );
+}
+
+KCModuleInfo::~KCModuleInfo()
+{
+ delete d;
+}
+
+void KCModuleInfo::Private::loadAll()
+{
+ allLoaded = true;
+
+ std::cout << "KCModuleInfo::Private::loadAll" << std::endl;
+
+// if( !service ) /* We have a bogus service. All get functions will return empty/zero values */
+ return;
+
+ // get the documentation path
+// doc = service->property( "X-DocPath", QVariant::String ).toString();
+// if (doc.isEmpty())
+// doc = service->property( "DocPath", QVariant::String ).toString();
+
+ // read weight
+// QVariant tmp = service->property( "X-KDE-Weight", QVariant::Int );
+// weight = tmp.isValid() ? tmp.toInt() : 100;
+
+ // factory handle
+// tmp = service->property("X-KDE-FactoryName", QVariant::String);
+// handle = tmp.isValid() ? tmp.toString() : lib;
+
+}
+
+QString KCModuleInfo::fileName() const
+{
+ return d->fileName;
+}
+
+QStringList KCModuleInfo::keywords() const
+{
+ return d->keywords;
+}
+
+QString KCModuleInfo::moduleName() const
+{
+ return d->name;
+}
+
+//KService::Ptr KCModuleInfo::service() const
+//{
+// return d->service;
+//}
+
+QString KCModuleInfo::comment() const
+{
+ return d->comment;
+}
+
+QString KCModuleInfo::icon() const
+{
+ return d->icon;
+}
+
+QString KCModuleInfo::library() const
+{
+ return d->lib;
+}
+
+QString KCModuleInfo::docPath() const
+{
+ if (!d->allLoaded)
+ d->loadAll();
+
+ return d->doc;
+}
+
+QString KCModuleInfo::handle() const
+{
+ if (!d->allLoaded)
+ d->loadAll();
+
+ return d->handle;
+}
+
+int KCModuleInfo::weight() const
+{
+ if (!d->allLoaded)
+ d->loadAll();
+
+ return d->weight;
+}
+
+// vim: ts=2 sw=2 et
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.h?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.h (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmoduleinfo.h Mon May 23 15:58:18 2011
@@ -0,0 +1,166 @@
+/*
+ Copyright (c) 1999 Matthias Hoelzer-Kluepfel
+ Copyright (c) 2000 Matthias Elter
+ Copyright (c) 2003 Daniel Molkentin
+ Copyright (c) 2003,2006 Matthias Kretz
+
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCMODULEINFO_H
+#define KCMODULEINFO_H
+
+//#include
+//#include
+
+#include <QString>
+#include <QStringList>
+
+class QString;
+class QStringList;
+
+/**
+ * A class that provides information about a KCModule
+ *
+ * KCModuleInfo provides various technical information, such as icon, library
+ * etc. about a KCModule.n
+ * @note Any values set with the set* functions is not
+ * written back with KCModuleInfo it only reads value from the desktop file.
+ *
+ * @internal
+ * @author Matthias Hoelzer-Kluepfel
+ * @author Matthias Elter
+ * @author Daniel Molkentin
+ *
+ */
+class KCModuleInfo // krazy:exclude=dpointer (implicitly shared)
+{
+
+public:
+
+ /**
+ * Constructs a KCModuleInfo.
+ * @note a KCModuleInfo object will have to be manually deleted, it is not
+ * done automatically for you.
+ * @param desktopFile the desktop file representing the module, or
+ * the name of the module.
+ */
+ KCModuleInfo(const QString& desktopFile);
+
+ /**
+ * Same as above but takes a KService::Ptr as argument.
+ *
+ * @note @p moduleInfo must be a valid pointer.
+ *
+ * @param moduleInfo specifies the module
+ */
+// KCModuleInfo( KService::Ptr moduleInfo );
+
+
+ /**
+ * Same as above but takes a KCModuleInfo as argument.
+ *
+ * @param rhs specifies the module
+ */
+ KCModuleInfo( const KCModuleInfo &rhs );
+
+ /**
+ * Same as above but creates an empty KCModuleInfo.
+ * You should not normally call this.
+ */
+ KCModuleInfo();
+
+ /**
+ * Assignment operator
+ */
+ KCModuleInfo &operator=( const KCModuleInfo &rhs );
+
+ /**
+ * Returns true if @p rhs describes the same KCModule as this object.
+ */
+ bool operator==( const KCModuleInfo &rhs ) const;
+
+ /**
+ * @return true if @p rhs is not equal itself
+ */
+ bool operator!=( const KCModuleInfo &rhs ) const;
+
+ /**
+ * Default destructor.
+ */
+ ~KCModuleInfo();
+
+ /**
+ * @return the filename of the .desktop file that describes the KCM
+ */
+ QString fileName() const;
+
+ /**
+ * @return the keywords associated with this KCM.
+ */
+ QStringList keywords() const;
+
+ /**
+ * @return the module\'s (translated) name
+ */
+ QString moduleName() const;
+
+ /**
+ * @return a KSharedPtr to KService created from the modules .desktop file
+ */
+// KService::Ptr service() const;
+
+ /**
+ * @return the module's (translated) comment field
+ */
+ QString comment() const;
+
+ /**
+ * @return the module's icon name
+ */
+ QString icon() const;
+
+ /**
+ * @return the path of the module's documentation
+ */
+ QString docPath() const;
+
+ /**
+ * @return the library name
+ */
+ QString library() const;
+
+ /**
+ * @return a handle (the contents of the X-KDE-FactoryName field if it exists,
+ * else the same as the library name)
+ */
+ QString handle() const;
+
+ /**
+ * @return the weight of the module which determines the order of the pages in
+ * the KCMultiDialog. It's set by the X-KDE-Weight field.
+ */
+ int weight() const;
+
+private:
+ class Private;
+ Private * d;
+};
+
+#endif // KCMODULEINFO_H
+
+// vim: ts=2 sw=2 et
Added: branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmodulemodel.cpp
URL: http://svn.opensuse.org/viewcvs/yast/branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmodulemodel.cpp?rev=64088&view=auto
==============================================================================
--- branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmodulemodel.cpp (added)
+++ branches/SuSE-Code-11-SP1-Branch/control-center/src/kcmodulemodel.cpp Mon May 23 15:58:18 2011
@@ -0,0 +1,245 @@
+/* This file is part of the KDE project
+ Copyright 2007 Will Stephenson
+
+ 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 <QStringList>
+
+#include "kcategorizedsortfilterproxymodel.h"
+#include "menuitem.h"
+#include <iostream>
+
+
+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
+{
+
+std::cout << "SystemSettingsProxyModel::filterAcceptsRow" << std::endl;
+
+ QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
+ MenuItem * mItem = index.data( Qt::UserRole ).value