m_itemLayout(IconsLayout),
m_modelRolesUpdater(0),
m_updateVisibleIndexRangeTimer(0),
- m_updateIconSizeTimer(0),
- m_minimumRolesWidths()
+ m_updateIconSizeTimer(0)
{
setAcceptDrops(true);
connect(m_updateIconSizeTimer, SIGNAL(timeout()), this, SLOT(updateIconSize()));
setVisibleRoles(QList<QByteArray>() << "name");
-
- updateMinimumRolesWidths();
}
KFileItemListView::~KFileItemListView()
return m_modelRolesUpdater ? m_modelRolesUpdater->enabledPlugins() : QStringList();
}
-QSizeF KFileItemListView::itemSizeHint(int index) const
-{
- const QHash<QByteArray, QVariant> values = model()->data(index);
- const KItemListStyleOption& option = styleOption();
- const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
-
- switch (m_itemLayout) {
- case IconsLayout: {
- const QString text = KStringHandler::preProcessWrap(values["name"].toString());
-
- const qreal maxWidth = itemSize().width() - 2 * option.padding;
- int textLinesCount = 0;
- QTextLine line;
-
- // Calculate the number of lines required for wrapping the name
- QTextOption textOption(Qt::AlignHCenter);
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
-
- QTextLayout layout(text, option.font);
- layout.setTextOption(textOption);
- layout.beginLayout();
- while ((line = layout.createLine()).isValid()) {
- line.setLineWidth(maxWidth);
- line.naturalTextWidth();
- ++textLinesCount;
- }
- layout.endLayout();
-
- // Add one line for each additional information
- textLinesCount += additionalRolesCount;
-
- const qreal height = textLinesCount * option.fontMetrics.height() +
- option.iconSize +
- option.padding * 3;
- return QSizeF(itemSize().width(), height);
- }
-
- case CompactLayout: {
- // For each row exactly one role is shown. Calculate the maximum required width that is necessary
- // to show all roles without horizontal clipping.
- qreal maximumRequiredWidth = 0.0;
-
- foreach (const QByteArray& role, visibleRoles()) {
- const QString text = KFileItemListWidget::roleText(role, values);
- const qreal requiredWidth = option.fontMetrics.width(text);
- maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth);
- }
-
- const qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth;
- const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.height());
- return QSizeF(width, height);
- }
-
- case DetailsLayout: {
- // The width will be determined dynamically by KFileItemListView::visibleRoleSizes()
- const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height());
- return QSizeF(-1, height);
- }
-
- default:
- Q_ASSERT(false);
- break;
- }
-
- return QSize();
-}
-
-qreal KFileItemListView::preferredRoleColumnWidth(const QByteArray& role, int index) const
-{
- const KItemListStyleOption& option = styleOption();
-
- qreal width = m_minimumRolesWidths.value(role, 0);
-
- const QHash<QByteArray, QVariant> values = model()->data(index);
- const QString text = KFileItemListWidget::roleText(role, values);
- if (!text.isEmpty()) {
- const qreal columnPadding = option.padding * 3;
- width = qMax(width, qreal(2 * columnPadding + option.fontMetrics.width(text)));
- }
-
- if (role == "name") {
- // Increase the width by the expansion-toggle and the current expansion level
- const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
- width += option.padding + (expandedParentsCount + 1) * itemSize().height() + KIconLoader::SizeSmall;
-
- // Increase the width by the required space for the icon
- width += option.padding * 2 + option.iconSize;
- }
-
- return width;
-}
-
QPixmap KFileItemListView::createDragPixmap(const QSet<int>& indexes) const
{
if (!model()) {
m_updateIconSizeTimer->setInterval(interval);
}
-void KFileItemListView::updateMinimumRolesWidths()
-{
- m_minimumRolesWidths.clear();
-
- const KItemListStyleOption& option = styleOption();
- const QString sizeText = QLatin1String("888888") + i18nc("@item:intable", "items");
- m_minimumRolesWidths.insert("size", option.fontMetrics.width(sizeText));
-}
-
void KFileItemListView::applyRolesToModel()
{
if (!model()) {
*/
QStringList enabledPlugins() const;
- /** @reimp */
- virtual QSizeF itemSizeHint(int index) const;
-
- /** @reimp */
- virtual qreal preferredRoleColumnWidth(const QByteArray& role, int index) const;
-
/** @reimp */
virtual QPixmap createDragPixmap(const QSet<int>& indexes) const;
private:
void updateLayoutOfVisibleItems();
void updateTimersInterval();
- void updateMinimumRolesWidths();
/**
* Applies the roles defined by KItemListView::visibleRoles() to the
QTimer* m_updateVisibleIndexRangeTimer;
QTimer* m_updateIconSizeTimer;
- // Cache for calculating visibleRoleSizes() in a fast way
- QHash<QByteArray, int> m_minimumRolesWidths;
-
friend class KFileItemListViewTest; // For unit testing
};
#include "kfileitemlistwidget.h"
#include "kfileitemclipboard_p.h"
+#include "kfileitemlistview.h"
#include "kfileitemmodel.h"
-#include "kitemlistview.h"
#include "kpixmapmodifier_p.h"
#include <KIcon>
return QRectF(pos, QSizeF(toggleSize, toggleSize));
}
-QString KFileItemListWidget::roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values)
+QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view)
{
- QString text;
- const QVariant roleValue = values.value(role);
+ const QHash<QByteArray, QVariant> values = view->model()->data(index);
+ const KItemListStyleOption& option = view->styleOption();
+ const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
- switch (roleTextId(role)) {
- case Name:
- case Permissions:
- case Owner:
- case Group:
- case Type:
- case Destination:
- case Path:
- text = roleValue.toString();
- break;
+ switch (static_cast<const KFileItemListView*>(view)->itemLayout()) {
+ case IconsLayout: {
+ const QString text = KStringHandler::preProcessWrap(values["name"].toString());
- case Size: {
- if (values.value("isDir").toBool()) {
- // The item represents a directory. Show the number of sub directories
- // instead of the file size of the directory.
- if (!roleValue.isNull()) {
- const int count = roleValue.toInt();
- if (count < 0) {
- text = i18nc("@item:intable", "Unknown");
- } else {
- text = i18ncp("@item:intable", "%1 item", "%1 items", count);
- }
- }
- } else {
- // Show the size in kilobytes (always round up)
- const KLocale* locale = KGlobal::locale();
- const int roundInc = (locale->binaryUnitDialect() == KLocale::MetricBinaryDialect) ? 499 : 511;
- const KIO::filesize_t size = roleValue.value<KIO::filesize_t>() + roundInc;
- text = locale->formatByteSize(size, 0, KLocale::DefaultBinaryDialect, KLocale::UnitKiloByte);
+ const qreal maxWidth = view->itemSize().width() - 2 * option.padding;
+ int textLinesCount = 0;
+ QTextLine line;
+
+ // Calculate the number of lines required for wrapping the name
+ QTextOption textOption(Qt::AlignHCenter);
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+
+ QTextLayout layout(text, option.font);
+ layout.setTextOption(textOption);
+ layout.beginLayout();
+ while ((line = layout.createLine()).isValid()) {
+ line.setLineWidth(maxWidth);
+ line.naturalTextWidth();
+ ++textLinesCount;
}
- break;
+ layout.endLayout();
+
+ // Add one line for each additional information
+ textLinesCount += additionalRolesCount;
+
+ const qreal height = textLinesCount * option.fontMetrics.height() +
+ option.iconSize +
+ option.padding * 3;
+ return QSizeF(view->itemSize().width(), height);
}
- case Date: {
- const QDateTime dateTime = roleValue.toDateTime();
- text = KGlobal::locale()->formatDateTime(dateTime);
- break;
+ case CompactLayout: {
+ // For each row exactly one role is shown. Calculate the maximum required width that is necessary
+ // to show all roles without horizontal clipping.
+ qreal maximumRequiredWidth = 0.0;
+
+ foreach (const QByteArray& role, view->visibleRoles()) {
+ const QString text = KFileItemListWidget::roleText(role, values);
+ const qreal requiredWidth = option.fontMetrics.width(text);
+ maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth);
+ }
+
+ const qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth;
+ const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.height());
+ return QSizeF(width, height);
+ }
+
+ case DetailsLayout: {
+ const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height());
+ return QSizeF(-1, height);
}
default:
break;
}
- return text;
+ return QSize();
+}
+
+qreal KFileItemListWidget::preferredRoleColumnWidth(const QByteArray& role,
+ int index,
+ const KItemListView* view)
+{
+ qreal width = 0;
+
+ const QHash<QByteArray, QVariant> values = view->model()->data(index);
+ const KItemListStyleOption& option = view->styleOption();
+
+ const QString text = KFileItemListWidget::roleText(role, values);
+ if (!text.isEmpty()) {
+ const qreal columnPadding = option.padding * 3;
+ width = qMax(width, qreal(2 * columnPadding + option.fontMetrics.width(text)));
+ }
+
+ if (role == "name") {
+ // Increase the width by the expansion-toggle and the current expansion level
+ const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
+ width += option.padding + (expandedParentsCount + 1) * view->itemSize().height() + KIconLoader::SizeSmall;
+
+ // Increase the width by the required space for the icon
+ width += option.padding * 2 + option.iconSize;
+ }
+
+ return width;
}
void KFileItemListWidget::invalidateCache()
return pixmap;
}
+void KFileItemListWidget::applyCutEffect(QPixmap& pixmap)
+{
+ KIconEffect* effect = KIconLoader::global()->iconEffect();
+ pixmap = effect->apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
+}
+
+void KFileItemListWidget::applyHiddenEffect(QPixmap& pixmap)
+{
+ KIconEffect::semiTransparent(pixmap);
+}
+
KFileItemListWidget::TextId KFileItemListWidget::roleTextId(const QByteArray& role)
{
static QHash<QByteArray, TextId> rolesHash;
return rolesHash.value(role);
}
-void KFileItemListWidget::applyCutEffect(QPixmap& pixmap)
+QString KFileItemListWidget::roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values)
{
- KIconEffect* effect = KIconLoader::global()->iconEffect();
- pixmap = effect->apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
-}
+ QString text;
+ const QVariant roleValue = values.value(role);
-void KFileItemListWidget::applyHiddenEffect(QPixmap& pixmap)
-{
- KIconEffect::semiTransparent(pixmap);
-}
+ switch (roleTextId(role)) {
+ case Name:
+ case Permissions:
+ case Owner:
+ case Group:
+ case Type:
+ case Destination:
+ case Path:
+ text = roleValue.toString();
+ break;
+
+ case Size: {
+ if (values.value("isDir").toBool()) {
+ // The item represents a directory. Show the number of sub directories
+ // instead of the file size of the directory.
+ if (!roleValue.isNull()) {
+ const int count = roleValue.toInt();
+ if (count < 0) {
+ text = i18nc("@item:intable", "Unknown");
+ } else {
+ text = i18ncp("@item:intable", "%1 item", "%1 items", count);
+ }
+ }
+ } else {
+ // Show the size in kilobytes (always round up)
+ const KLocale* locale = KGlobal::locale();
+ const int roundInc = (locale->binaryUnitDialect() == KLocale::MetricBinaryDialect) ? 499 : 511;
+ const KIO::filesize_t size = roleValue.value<KIO::filesize_t>() + roundInc;
+ text = locale->formatByteSize(size, 0, KLocale::DefaultBinaryDialect, KLocale::UnitKiloByte);
+ }
+ break;
+ }
+
+ case Date: {
+ const QDateTime dateTime = roleValue.toDateTime();
+ text = KGlobal::locale()->formatDateTime(dateTime);
+ break;
+ }
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ return text;
+}
#include "kfileitemlistwidget.moc"
#include <QPointF>
#include <QStaticText>
+class KItemListView;
+class KItemListStyleOption;
+
class LIBDOLPHINPRIVATE_EXPORT KFileItemListWidget : public KItemListWidget
{
Q_OBJECT
virtual QRectF selectionToggleRect() const;
/**
- * @return Shown string for the role \p role of the item with the values \p values.
+ * Implementation of KItemListWidgetCreatorBase::itemSizeHint() when
+ * using the KItemListWidgetCreator-template.
+ *
+ * @see KItemListView
*/
- // TODO: Move this method to a helper class shared by KFileItemListWidget and
- // KFileItemListView to share information that is required to calculate the size hints
- // in KFileItemListView and to represent the actual data in KFileItemListWidget.
- static QString roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values);
+ static QSizeF itemSizeHint(int index, const KItemListView* view);
+
+ /**
+ * Implementation of KItemListWidgetCreatorBase::preferredRoleColumnWidth() when
+ * using the KItemListWidgetCreator-template.
+ *
+ * @see KItemListView
+ */
+ static qreal preferredRoleColumnWidth(const QByteArray& role, int index, const KItemListView* view);
protected:
/**
void drawSiblingsInformation(QPainter* painter);
static QPixmap pixmapForIcon(const QString& name, int size);
- static TextId roleTextId(const QByteArray& role);
static void applyCutEffect(QPixmap& pixmap);
static void applyHiddenEffect(QPixmap& pixmap);
+ static TextId roleTextId(const QByteArray& role);
+
+ /**
+ * @return Shown string for the role \p role of the item with the values \p values.
+ */
+ static QString roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values);
private:
bool m_isCut;
QSizeF KItemListView::itemSizeHint(int index) const
{
- Q_UNUSED(index);
- return itemSize();
-}
-
-qreal KItemListView::preferredRoleColumnWidth(const QByteArray& role, int index) const
-{
- Q_UNUSED(role);
- Q_UNUSED(index);
- return 100;
+ return m_widgetCreator->itemSizeHint(index, this);
}
void KItemListView::setSupportsItemExpanding(bool supportsExpanding)
for (int i = startIndex; i <= endIndex; ++i) {
foreach (const QByteArray& visibleRole, visibleRoles()) {
qreal maxWidth = widths.value(visibleRole, 0);
- const qreal width = preferredRoleColumnWidth(visibleRole, i);
+ const qreal width = m_widgetCreator->preferredRoleColumnWidth(visibleRole, i, this);
maxWidth = qMax(width, maxWidth);
widths.insert(visibleRole, maxWidth);
}
/**
* @return Required size for the item with the index \p index.
- * Per default KItemListView::itemSize() is returned.
- * When reimplementing this method it is recommended to
- * also reimplement KItemListView::itemSizeHintUpdateRequired().
+ * The returned value might be larger than KItemListView::itemSize().
+ * In this case the layout grid will be stretched to assure an
+ * unclipped item.
*/
- virtual QSizeF itemSizeHint(int index) const;
-
- /**
- * @return The preferred column-width of the given \a role for the item
- * with the index \a index.
- */
- virtual qreal preferredRoleColumnWidth(const QByteArray& role, int index) const;
+ QSizeF itemSizeHint(int index) const;
/**
* If set to true, items having child-items can be expanded to show the child-items as
* @brief Base class for creating KItemListWidgets.
*
* It is recommended that applications simply use the KItemListWidgetCreator-template class.
- * For a custom implementation the methods create() and recyle() must be reimplemented.
- * The intention of the widget creator is to prevent repetitive and expensive instantiations and
- * deletions of KItemListWidgets by recycling existing widget instances.
+ * For a custom implementation the methods create(), itemSizeHint() and preferredColumnWith()
+ * must be reimplemented. The intention of the widget creator is to prevent repetitive and
+ * expensive instantiations and deletions of KItemListWidgets by recycling existing widget
+ * instances.
*/
class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreatorBase : public KItemListCreatorBase
{
public:
virtual ~KItemListWidgetCreatorBase();
+
virtual KItemListWidget* create(KItemListView* view) = 0;
+
virtual void recycle(KItemListWidget* widget);
+
+ virtual QSizeF itemSizeHint(int index, const KItemListView* view) const = 0;
+
+ virtual qreal preferredRoleColumnWidth(const QByteArray& role,
+ int index,
+ const KItemListView* view) const = 0;
};
+/**
+ * @brief Template class for creating KItemListWidgets.
+ *
+ * The template class must provide the following two static methods:
+ * - QSizeF itemSizeHint(int index, const KItemListView* view)
+ * - preferredRoleColumnWidth(const QByteArray& role, int index, const KItemListView* view)
+ * Those static methods are used as implementation for
+ * KItemListWidgetCreatorBase::itemSizeHint() and
+ * KItemListWidgetCreatorBase::preferedRoleColumnWidth().
+ */
template <class T>
class KItemListWidgetCreator : public KItemListWidgetCreatorBase
{
public:
virtual ~KItemListWidgetCreator();
+
virtual KItemListWidget* create(KItemListView* view);
+
+ virtual QSizeF itemSizeHint(int index, const KItemListView* view) const;
+
+ virtual qreal preferredRoleColumnWidth(const QByteArray& role,
+ int index,
+ const KItemListView* view) const;
};
template <class T>
return widget;
}
+template<class T>
+QSizeF KItemListWidgetCreator<T>::itemSizeHint(int index, const KItemListView* view) const
+{
+ return T::itemSizeHint(index, view);
+}
+
+template<class T>
+qreal KItemListWidgetCreator<T>::preferredRoleColumnWidth(const QByteArray& role,
+ int index,
+ const KItemListView* view) const
+{
+ return T::preferredRoleColumnWidth(role, index, view);
+}
+
/**
* @brief Base class for creating KItemListGroupHeaders.
*