/**
  * This file is part of the KDE project
  * Copyright (C) 2007, 2009 Rafael Fernández López <ereslibre@kde.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public License
  * along with this library; see the file COPYING.LIB.  If not, write to
  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301, USA.
  */

#ifndef KCATEGORIZEDVIEW_P_H
#define KCATEGORIZEDVIEW_P_H

class KCategorizedSortFilterProxyModel;
class KCategoryDrawer;
class KCategoryDrawerV2;
class KCategoryDrawerV3;

/**
  * @internal
  */
class KCategorizedView::Private
{
public:
    struct Block;
    struct Item;

    Private(KCategorizedView *q);
    ~Private();

    /**
      * @return whether this view has all required elements to be categorized.
      */
    bool isCategorized() const;

    /**
      * @return the block rect for the representative @p representative.
      */
    QStyleOptionViewItemV4 blockRect(const QModelIndex &representative);

    /**
      * Returns the first and last element that intersects with rect.
      *
      * @note see that here we cannot take out items between first and last (as we could
      *       do with the rubberband).
      *
      * Complexity: O(log(n)) where n is model()->rowCount().
      */
    QPair<QModelIndex, QModelIndex> intersectingIndexesWithRect(const QRect &rect) const;

    /**
      * Returns the position of the block of @p category.
      *
      * Complexity: O(n) where n is the number of different categories when the block has been
      *             marked as in quarantine. O(1) the rest of the times (the vast majority).
      */
    QPoint blockPosition(const QString &category);

    /**
      * Returns the height of the block determined by @p category.
      */
    int blockHeight(const QString &category);

    /**
      * Returns the actual viewport width.
      */
    int viewportWidth() const;

    /**
      * Marks all elements as in quarantine.
      *
      * Complexity: O(n) where n is model()->rowCount().
      *
      * @warning this is an expensive operation
      */
    void regenerateAllElements();

    /**
      * Update internal information, and keep sync with the real information that the model contains.
      */
    void rowsInserted(const QModelIndex &parent, int start, int end);

    /**
      * Returns @p rect in viewport terms, taking in count horizontal and vertical offsets.
      */
    QRect mapToViewport(const QRect &rect) const;

    /**
      * Returns @p rect in absolute terms, converted from viewport position.
      */
    QRect mapFromViewport(const QRect &rect) const;

    /**
      * Returns the height of the highest element in last row. This is only applicable if there is
      * no grid set and uniformItemSizes is false.
      *
      * @param block in which block are we searching. Necessary to stop the search if we hit the
      *              first item in this block.
      */
    int highestElementInLastRow(const Block &block) const;

    /**
      * Returns whether the view has a valid grid size.
      */
    bool hasGrid() const;

    /**
      * Returns the category for the given index.
      */
    QString categoryForIndex(const QModelIndex &index) const;

    /**
      * Updates the visual rect for item when flow is LeftToRight.
      */
    void leftToRightVisualRect(const QModelIndex &index, Item &item,
                               const Block &block, const QPoint &blockPos) const;

    /**
      * Updates the visual rect for item when flow is TopToBottom.
      * @note we only support viewMode == ListMode in this case.
      */
    void topToBottomVisualRect(const QModelIndex &index, Item &item,
                               const Block &block, const QPoint &blockPos) const;

    /**
      * Called when expand or collapse has been clicked on the category drawer.
      */
    void _k_slotCollapseOrExpandClicked(QModelIndex);

    KCategorizedView *q;
    KCategorizedSortFilterProxyModel *proxyModel;
    KCategoryDrawer *categoryDrawer;
    int categorySpacing;
    bool alternatingBlockColors;
    bool collapsibleBlocks;

    Block *hoveredBlock;
    QString hoveredCategory;
    QModelIndex hoveredIndex;

    QPoint pressedPosition;
    QRect rubberBandRect;

    QHash<QString, Block> blocks;
};

#endif // KCATEGORIZEDVIEW_P_H