From 46f93311afc9f1e2afc306f63cee0e4f462758e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 11 Mar 2013 22:19:17 +0100 Subject: Instance view, model, delegate. --- .../include/kcategorizedsortfilterproxymodel.h | 175 +++++++++++ libgroupview/include/kcategorizedview.h | 322 +++++++++++++++++++++ libgroupview/include/kcategorydrawer.h | 179 ++++++++++++ libgroupview/include/libgroupview_config.h | 27 ++ 4 files changed, 703 insertions(+) create mode 100644 libgroupview/include/kcategorizedsortfilterproxymodel.h create mode 100644 libgroupview/include/kcategorizedview.h create mode 100644 libgroupview/include/kcategorydrawer.h create mode 100644 libgroupview/include/libgroupview_config.h (limited to 'libgroupview/include') diff --git a/libgroupview/include/kcategorizedsortfilterproxymodel.h b/libgroupview/include/kcategorizedsortfilterproxymodel.h new file mode 100644 index 00000000..be83f3be --- /dev/null +++ b/libgroupview/include/kcategorizedsortfilterproxymodel.h @@ -0,0 +1,175 @@ +/* + * 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_H +#define KCATEGORIZEDSORTFILTERPROXYMODEL_H + +#include + +#include + +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 + : public QSortFilterProxyModel +{ +public: + enum AdditionalRoles + { + // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) + // to define additional roles. + CategoryDisplayRole = 0x17CE990A, ///< This role is used for asking the category to a given index + + CategorySortRole = 0x27857E60 ///< This role is used for sorting categories. You can return a + ///< string or a long long value. Strings will be sorted alphabetically + ///< while long long will be sorted by their value. Please note that this + ///< value won't be shown on the view, is only for sorting purposes. What will + ///< be shown as "Category" on the view will be asked with the role + ///< CategoryDisplayRole. + }; + + KCategorizedSortFilterProxyModel ( QObject *parent = 0 ); + virtual ~KCategorizedSortFilterProxyModel(); + + /** + * Overridden from QSortFilterProxyModel. Sorts the source model using + * @p column for the given @p order. + */ + virtual void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder ); + + /** + * @return whether the model is categorized or not. Disabled by default. + */ + bool isCategorizedModel() const; + + /** + * Enables or disables the categorization feature. + * + * @param categorizedModel whether to enable or disable the categorization feature. + */ + void setCategorizedModel ( bool categorizedModel ); + + /** + * @return the column being used for sorting. + */ + int sortColumn() const; + + /** + * @return the sort order being used for sorting. + */ + Qt::SortOrder sortOrder() const; + + /** + * Set if the sorting using CategorySortRole will use a natural comparison + * in the case that strings were returned. If enabled, QString::localeAwareCompare + * will be used for sorting. + * + * @param sortCategoriesByNaturalComparison whether to sort using a natural comparison or not. + */ + void setSortCategoriesByNaturalComparison ( bool sortCategoriesByNaturalComparison ); + + /** + * @return whether it is being used a natural comparison for sorting. Enabled by default. + */ + bool sortCategoriesByNaturalComparison() const; + +protected: + /** + * Overridden from QSortFilterProxyModel. If you are subclassing + * KCategorizedSortFilterProxyModel, you will probably not need to reimplement this + * method. + * + * It calls compareCategories() to sort by category. If the both items are in the + * same category (i.e. compareCategories returns 0), then subSortLessThan is called. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + * + * @warning You usually won't need to reimplement this method when subclassing + * from KCategorizedSortFilterProxyModel. + */ + virtual bool lessThan ( const QModelIndex &left, const QModelIndex &right ) const; + + /** + * This method has a similar purpose as lessThan() has on QSortFilterProxyModel. + * It is used for sorting items that are in the same category. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + */ + virtual bool subSortLessThan ( const QModelIndex &left, const QModelIndex &right ) const; + + /** + * This method compares the category of the @p left index with the category + * of the @p right index. + * + * Internally and if not reimplemented, this method will ask for @p left and + * @p right models for role CategorySortRole. In order to correctly sort + * categories, the data() metod of the model should return a qlonglong (or numeric) value, or + * a QString object. QString objects will be sorted with QString::localeAwareCompare if + * sortCategoriesByNaturalComparison() is true. + * + * @note Please have present that: + * QString(QChar(QChar::ObjectReplacementCharacter)) > + * QString(QChar(QChar::ReplacementCharacter)) > + * [ all possible strings ] > + * QString(); + * + * This means that QString() will be sorted the first one, while + * QString(QChar(QChar::ObjectReplacementCharacter)) and + * QString(QChar(QChar::ReplacementCharacter)) will be sorted in last + * position. + * + * @warning Please note that data() method of the model should return always + * information of the same type. If you return a QString for an index, + * you should return always QStrings for all indexes for role CategorySortRole + * in order to correctly sort categories. You can't mix by returning + * a QString for one index, and a qlonglong for other. + * + * @note If you need a more complex layout, you will have to reimplement this + * method. + * + * @return A negative value if the category of @p left should be placed before the + * category of @p right. 0 if @p left and @p right are on the same category, and + * a positive value if the category of @p left should be placed after the + * category of @p right. + */ + virtual int compareCategories ( const QModelIndex &left, const QModelIndex &right ) const; + +private: + class Private; + Private *const d; +}; + + +#endif // KCATEGORIZEDSORTFILTERPROXYMODEL_H diff --git a/libgroupview/include/kcategorizedview.h b/libgroupview/include/kcategorizedview.h new file mode 100644 index 00000000..04c2f5cc --- /dev/null +++ b/libgroupview/include/kcategorizedview.h @@ -0,0 +1,322 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007, 2009 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 + +class KCategoryDrawer; + +/** + * @short Item view for listing items in a categorized fashion optionally + * + * KCategorizedView basically has the same functionality as QListView, only that it also lets you + * layout items in a way that they are categorized visually. + * + * For it to work you will need to set a KCategorizedSortFilterProxyModel and a KCategoryDrawer + * with methods setModel() and setCategoryDrawer() respectively. Also, the model will need to be + * flagged as categorized with KCategorizedSortFilterProxyModel::setCategorizedModel(true). + * + * The way it works (if categorization enabled): + * + * - When sorting, it does more things than QListView does. It will ask the model for the + * special role CategorySortRole (@see KCategorizedSortFilterProxyModel). This can return + * a QString or an int in order to tell the view the order of categories. In this sense, for + * instance, if we are sorting by name ascending, "A" would be before than "B". If we are + * sorting by size ascending, 512 bytes would be before 1024 bytes. This way categories are + * also sorted. + * + * - When the view has to paint, it will ask the model with the role CategoryDisplayRole + * (@see KCategorizedSortFilterProxyModel). It will for instance return "F" for "foo.pdf" if + * we are sorting by name ascending, or "Small" if a certain item has 100 bytes, for example. + * + * For drawing categories, KCategoryDrawer will be used. You can inherit this class to do your own + * drawing. + * + * @note All examples cited before talk about filesystems and such, but have present that this + * is a completely generic class, and it can be used for whatever your purpose is. For + * instance when talking about animals, you can separate them by "Mammal" and "Oviparous". In + * this very case, for example, the CategorySortRole and the CategoryDisplayRole could be the + * same ("Mammal" and "Oviparous"). + * + * @note There is a really performance boost if CategorySortRole returns an int instead of a QString. + * Have present that this role is asked (n * log n) times when sorting and compared. Comparing + * ints is always faster than comparing strings, whithout mattering how fast the string + * comparison is. Consider thinking of a way of returning ints instead of QStrings if your + * model can contain a high number of items. + * + * @warning Note that for really drawing items in blocks you will need some things to be done: + * - The model set to this view has to be (or inherit if you want to do special stuff + * in it) KCategorizedSortFilterProxyModel. + * - This model needs to be set setCategorizedModel to true. + * - Set a category drawer by calling setCategoryDrawer. + * + * @see KCategorizedSortFilterProxyModel, KCategoryDrawer + * + * @author Rafael Fernández López + */ +class KDEUI_EXPORT KCategorizedView + : public QListView +{ + Q_OBJECT + Q_PROPERTY ( int categorySpacing READ categorySpacing WRITE setCategorySpacing ) + Q_PROPERTY ( bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors ) + Q_PROPERTY ( bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks ) + +public: + KCategorizedView ( QWidget *parent = 0 ); + + ~KCategorizedView(); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void setModel ( QAbstractItemModel *model ); + + /** + * Calls to setGridSizeOwn(). + */ + void setGridSize ( const QSize &size ); + + /** + * @warning note that setGridSize is not virtual in the base class (QListView), so if you are + * calling to this method, make sure you have a KCategorizedView pointer around. This + * means that something like: + * @code + * QListView *lv = new KCategorizedView(); + * lv->setGridSize(mySize); + * @endcode + * + * will not call to the expected setGridSize method. Instead do something like this: + * + * @code + * QListView *lv; + * ... + * KCategorizedView *cv = qobject_cast(lv); + * if (cv) { + * cv->setGridSizeOwn(mySize); + * } else { + * lv->setGridSize(mySize); + * } + * @endcode + * + * @note this method will call to QListView::setGridSize among other operations. + * + * @since 4.4 + */ + void setGridSizeOwn ( const QSize &size ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QRect visualRect ( const QModelIndex &index ) const; + + /** + * Returns the current category drawer. + */ + KCategoryDrawer *categoryDrawer() const; + + /** + * The category drawer that will be used for drawing categories. + */ + void setCategoryDrawer ( KCategoryDrawer *categoryDrawer ); + + /** + * @return Category spacing. The spacing between categories. + * + * @since 4.4 + */ + int categorySpacing() const; + + /** + * Stablishes the category spacing. This is the spacing between categories. + * + * @since 4.4 + */ + void setCategorySpacing ( int categorySpacing ); + + /** + * @return Whether blocks should be drawn with alternating colors. + * + * @since 4.4 + */ + bool alternatingBlockColors() const; + + /** + * Sets whether blocks should be drawn with alternating colors. + * + * @since 4.4 + */ + void setAlternatingBlockColors ( bool enable ); + + /** + * @return Whether blocks can be collapsed or not. + * + * @since 4.4 + */ + bool collapsibleBlocks() const; + + /** + * Sets whether blocks can be collapsed or not. + * + * @since 4.4 + */ + void setCollapsibleBlocks ( bool enable ); + + /** + * @return Block of indexes that are into @p category. + * + * @since 4.5 + */ + QModelIndexList block ( const QString &category ); + + /** + * @return Block of indexes that are represented by @p representative. + * + * @since 4.5 + */ + QModelIndexList block ( const QModelIndex &representative ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QModelIndex indexAt ( const QPoint &point ) const; + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void reset(); + +protected: + /** + * Reimplemented from QWidget. + */ + virtual void paintEvent ( QPaintEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void resizeEvent ( QResizeEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void setSelection ( const QRect &rect, + QItemSelectionModel::SelectionFlags flags ); + + /** + * Reimplemented from QWidget. + */ + virtual void mouseMoveEvent ( QMouseEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void mousePressEvent ( QMouseEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void mouseReleaseEvent ( QMouseEvent *event ); + + /** + * Reimplemented from QWidget. + */ + virtual void leaveEvent ( QEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void startDrag ( Qt::DropActions supportedActions ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragMoveEvent ( QDragMoveEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragEnterEvent ( QDragEnterEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragLeaveEvent ( QDragLeaveEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dropEvent ( QDropEvent *event ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QModelIndex moveCursor ( CursorAction cursorAction, + Qt::KeyboardModifiers modifiers ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void rowsAboutToBeRemoved ( const QModelIndex &parent, + int start, + int end ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void updateGeometries(); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void currentChanged ( const QModelIndex ¤t, + const QModelIndex &previous ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dataChanged ( const QModelIndex &topLeft, + const QModelIndex &bottomRight ); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void rowsInserted ( const QModelIndex &parent, + int start, + int end ); + +protected Q_SLOTS: + /** + * @internal + * Reposition items as needed. + */ + virtual void slotLayoutChanged(); + virtual void slotCollapseOrExpandClicked ( QModelIndex ); + +private: + class Private; + Private *const d; +}; + +#endif // KCATEGORIZEDVIEW_H diff --git a/libgroupview/include/kcategorydrawer.h b/libgroupview/include/kcategorydrawer.h new file mode 100644 index 00000000..aa561f0d --- /dev/null +++ b/libgroupview/include/kcategorydrawer.h @@ -0,0 +1,179 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007, 2009 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 + +#include +#include + +class QPainter; +class QModelIndex; +class QStyleOption; +class KCategorizedView; + + +/** + * @since 4.5 + */ +class LIBGROUPVIEW_EXPORT KCategoryDrawer + : public QObject +{ + friend class KCategorizedView; + Q_OBJECT + + +public: + KCategoryDrawer ( KCategorizedView *view ); + virtual ~KCategoryDrawer(); + + /** + * @return The view this category drawer is associated with. + */ + KCategorizedView *view() const; + + /** + * 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; + + /** + * @return The category height for the category representated by index @p index with + * style options @p option. + */ + virtual int categoryHeight ( const QModelIndex &index, const QStyleOption &option ) const; + + //TODO KDE5: make virtual as leftMargin + /** + * @note 0 by default + * + * @since 4.4 + */ + int leftMargin() const; + + /** + * @note call to this method on the KCategoryDrawer constructor to set the left margin + * + * @since 4.4 + */ + void setLeftMargin ( int leftMargin ); + + //TODO KDE5: make virtual as rightMargin + /** + * @note 0 by default + * + * @since 4.4 + */ + int rightMargin() const; + + /** + * @note call to this method on the KCategoryDrawer constructor to set the right margin + * + * @since 4.4 + */ + void setRightMargin ( int rightMargin ); + + KCategoryDrawer &operator= ( const KCategoryDrawer &cd ); +protected: + /** + * Method called when the mouse button has been pressed. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonPressed ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse button has been released. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonReleased ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse has been moved. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + */ + virtual void mouseMoved ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse button has been double clicked. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonDoubleClicked ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event ); + + /** + * Method called when the mouse button has left this block. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + */ + virtual void mouseLeft ( const QModelIndex &index, const QRect &blockRect ); + +private: + class Private; + Private *const d; +Q_SIGNALS: + /** + * This signal becomes emitted when collapse or expand has been clicked. + */ + void collapseOrExpandClicked ( const QModelIndex &index ); + + /** + * Emit this signal on your subclass implementation to notify that something happened. Usually + * this will be triggered when you have received an event, and its position matched some "hot spot". + * + * You give this action the integer you want, and having connected this signal to your code, + * the connected slot can perform the needed changes (view, model, selection model, delegate...) + */ + void actionRequested ( int action, const QModelIndex &index ); +}; + +#endif // KCATEGORYDRAWER_H diff --git a/libgroupview/include/libgroupview_config.h b/libgroupview/include/libgroupview_config.h new file mode 100644 index 00000000..86bed139 --- /dev/null +++ b/libgroupview/include/libgroupview_config.h @@ -0,0 +1,27 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#ifndef LIBINSTANCE_CONFIG_H +//#define LIBINSTANCE_CONFIG_H + +#include + +#ifdef LIBGROUPVIEW_LIBRARY +# define LIBGROUPVIEW_EXPORT Q_DECL_EXPORT +#else +# define LIBGROUPVIEW_EXPORT Q_DECL_IMPORT +#endif + +//#endif // LIBINSTANCE_CONFIG_H -- cgit v1.2.3