kitemviews/kitemlistview.cpp
kitemviews/kitemlistwidget.cpp
kitemviews/kitemmodelbase.cpp
+ kitemviews/kstandarditem.cpp
+ kitemviews/kstandarditemlistview.cpp
+ kitemviews/kstandarditemlistwidget.cpp
+ kitemviews/kstandarditemmodel.cpp
kitemviews/private/kfileitemclipboard.cpp
kitemviews/private/kfileitemmodeldirlister.cpp
kitemviews/private/kfileitemmodelsortalgorithm.cpp
settings/viewpropertiesdialog.cpp
settings/viewpropsprogressinfo.cpp
views/dolphinfileitemlistwidget.cpp
- views/dolphinitemlistcontainer.cpp
+ views/dolphinitemlistview.cpp
views/dolphinnewfilemenuobserver.cpp
views/dolphinplacesmodel.cpp
views/dolphinremoteencoding.cpp
QList<QAction*> placesActions;
placesActions.append(separator);
placesActions.append(lockLayoutAction);
- placesPanel->addActions(placesActions);
- placesPanel->setModel(DolphinPlacesModel::instance());
- placesPanel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ //placesPanel->addActions(placesActions);
+ //placesPanel->setModel(DolphinPlacesModel::instance());
+ //placesPanel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
placesDock->setWidget(placesPanel);
QAction* placesAction = placesDock->toggleViewAction();
createPanelAction(KIcon("bookmarks"), Qt::Key_F9, placesAction, "show_places_panel");
addDockWidget(Qt::LeftDockWidgetArea, placesDock);
- connect(placesPanel, SIGNAL(urlChanged(KUrl,Qt::MouseButtons)),
- this, SLOT(handlePlacesClick(KUrl,Qt::MouseButtons)));
+ //connect(placesPanel, SIGNAL(urlChanged(KUrl,Qt::MouseButtons)),
+ // this, SLOT(handlePlacesClick(KUrl,Qt::MouseButtons)));
connect(this, SIGNAL(urlChanged(KUrl)),
placesPanel, SLOT(setUrl(KUrl)));
connect(placesDock, SIGNAL(visibilityChanged(bool)),
}
KFileItemListView::KFileItemListView(QGraphicsWidget* parent) :
- KItemListView(parent),
- m_itemLayout(IconsLayout),
+ KStandardItemListView(parent),
m_modelRolesUpdater(0),
m_updateVisibleIndexRangeTimer(0),
m_updateIconSizeTimer(0)
setAcceptDrops(true);
setScrollOrientation(Qt::Vertical);
- setWidgetCreator(new KItemListWidgetCreator<KFileItemListWidget>());
- setGroupHeaderCreator(new KItemListGroupHeaderCreator<KFileItemListGroupHeader>());
m_updateVisibleIndexRangeTimer = new QTimer(this);
m_updateVisibleIndexRangeTimer->setSingleShot(true);
m_updateIconSizeTimer->setInterval(ShortInterval);
connect(m_updateIconSizeTimer, SIGNAL(timeout()), this, SLOT(updateIconSize()));
- setVisibleRoles(QList<QByteArray>() << "name");
+ setVisibleRoles(QList<QByteArray>() << "text");
}
KFileItemListView::~KFileItemListView()
{
- // The group headers are children of the widgets created by
- // widgetCreator(). So it is mandatory to delete the group headers
- // first.
- delete groupHeaderCreator();
- delete widgetCreator();
-
delete m_modelRolesUpdater;
m_modelRolesUpdater = 0;
}
void KFileItemListView::setPreviewsShown(bool show)
{
- if (m_modelRolesUpdater) {
+ if (!m_modelRolesUpdater) {
+ return;
+ }
+
+ if (m_modelRolesUpdater->previewsShown() != show) {
+ beginTransaction();
m_modelRolesUpdater->setPreviewsShown(show);
+ onPreviewsShownChanged(show);
+ endTransaction();
}
}
return m_modelRolesUpdater ? m_modelRolesUpdater->enlargeSmallPreviews() : false;
}
-void KFileItemListView::setItemLayout(Layout layout)
-{
- if (m_itemLayout != layout) {
- const bool updateRoles = (m_itemLayout == DetailsLayout || layout == DetailsLayout);
- m_itemLayout = layout;
- if (updateRoles) {
- // The details-layout requires some invisible roles that
- // must be added to the model if the new layout is "details".
- // If the old layout was "details" the roles will get removed.
- applyRolesToModel();
- }
- updateLayoutOfVisibleItems();
- }
-}
-
-KFileItemListView::Layout KFileItemListView::itemLayout() const
-{
- return m_itemLayout;
-}
-
void KFileItemListView::setEnabledPlugins(const QStringList& list)
{
if (m_modelRolesUpdater) {
return dragPixmap;
}
-void KFileItemListView::initializeItemListWidget(KItemListWidget* item)
+KItemListWidgetCreatorBase* KFileItemListView::defaultWidgetCreator() const
{
- KFileItemListWidget* fileItemListWidget = static_cast<KFileItemListWidget*>(item);
-
- switch (m_itemLayout) {
- case IconsLayout: fileItemListWidget->setLayout(KFileItemListWidget::IconsLayout); break;
- case CompactLayout: fileItemListWidget->setLayout(KFileItemListWidget::CompactLayout); break;
- case DetailsLayout: fileItemListWidget->setLayout(KFileItemListWidget::DetailsLayout); break;
- default: Q_ASSERT(false); break;
- }
+ return new KItemListWidgetCreator<KFileItemListWidget>();
+}
- fileItemListWidget->setSupportsItemExpanding(supportsItemExpanding());
+KItemListGroupHeaderCreatorBase* KFileItemListView::defaultGroupHeaderCreator() const
+{
+ return new KItemListGroupHeaderCreator<KFileItemListGroupHeader>();
}
-bool KFileItemListView::itemSizeHintUpdateRequired(const QSet<QByteArray>& changedRoles) const
+void KFileItemListView::onPreviewsShownChanged(bool shown)
{
- // Even if the icons have a different size they are always aligned within
- // the area defined by KItemStyleOption.iconSize and hence result in no
- // change of the item-size.
- const bool containsIconName = changedRoles.contains("iconName");
- const bool containsIconPixmap = changedRoles.contains("iconPixmap");
- const int count = changedRoles.count();
+ Q_UNUSED(shown);
+}
- const bool iconChanged = (containsIconName && containsIconPixmap && count == 2) ||
- (containsIconName && count == 1) ||
- (containsIconPixmap && count == 1);
- return !iconChanged;
+void KFileItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous)
+{
+ if (previous == DetailsLayout || current == DetailsLayout) {
+ // The details-layout requires some invisible roles that
+ // must be added to the model if the new layout is "details".
+ // If the old layout was "details" the roles will get removed.
+ applyRolesToModel();
+ }
+ KStandardItemListView::onItemLayoutChanged(current, previous);
+ triggerVisibleIndexRangeUpdate();
}
void KFileItemListView::onModelChanged(KItemModelBase* current, KItemModelBase* previous)
{
- Q_UNUSED(previous);
Q_ASSERT(qobject_cast<KFileItemModel*>(current));
+ KStandardItemListView::onModelChanged(current, previous);
delete m_modelRolesUpdater;
- m_modelRolesUpdater = new KFileItemModelRolesUpdater(static_cast<KFileItemModel*>(current), this);
- m_modelRolesUpdater->setIconSize(availableIconSize());
+ m_modelRolesUpdater = 0;
- applyRolesToModel();
+ if (current) {
+ m_modelRolesUpdater = new KFileItemModelRolesUpdater(static_cast<KFileItemModel*>(current), this);
+ m_modelRolesUpdater->setIconSize(availableIconSize());
+
+ applyRolesToModel();
+ }
}
void KFileItemListView::onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous)
{
- Q_UNUSED(current);
- Q_UNUSED(previous);
- updateLayoutOfVisibleItems();
+ KStandardItemListView::onScrollOrientationChanged(current, previous);
+ triggerVisibleIndexRangeUpdate();
}
void KFileItemListView::onItemSizeChanged(const QSizeF& current, const QSizeF& previous)
void KFileItemListView::onScrollOffsetChanged(qreal current, qreal previous)
{
- Q_UNUSED(current);
- Q_UNUSED(previous);
+ KStandardItemListView::onScrollOffsetChanged(current, previous);
triggerVisibleIndexRangeUpdate();
}
void KFileItemListView::onVisibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous)
{
- Q_UNUSED(current);
- Q_UNUSED(previous);
+ KStandardItemListView::onVisibleRolesChanged(current, previous);
applyRolesToModel();
}
void KFileItemListView::onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous)
{
- Q_UNUSED(current);
- Q_UNUSED(previous);
+ KStandardItemListView::onStyleOptionChanged(current, previous);
triggerIconSizeUpdate();
}
void KFileItemListView::onSupportsItemExpandingChanged(bool supportsExpanding)
{
- Q_UNUSED(supportsExpanding);
applyRolesToModel();
- updateLayoutOfVisibleItems();
+ KStandardItemListView::onSupportsItemExpandingChanged(supportsExpanding);
+ triggerVisibleIndexRangeUpdate();
}
void KFileItemListView::onTransactionBegin()
{
- m_modelRolesUpdater->setPaused(true);
+ if (m_modelRolesUpdater) {
+ m_modelRolesUpdater->setPaused(true);
+ }
}
void KFileItemListView::onTransactionEnd()
{
+ if (!m_modelRolesUpdater) {
+ return;
+ }
+
// Only unpause the model-roles-updater if no timer is active. If one
// timer is still active the model-roles-updater will be unpaused later as
// soon as the timer has been exceeded.
void KFileItemListView::resizeEvent(QGraphicsSceneResizeEvent* event)
{
- KItemListView::resizeEvent(event);
+ KStandardItemListView::resizeEvent(event);
triggerVisibleIndexRangeUpdate();
}
void KFileItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
{
- KItemListView::slotItemsRemoved(itemRanges);
+ KStandardItemListView::slotItemsRemoved(itemRanges);
updateTimersInterval();
}
applyRolesToModel();
}
- KItemListView::slotSortRoleChanged(current, previous);
+ KStandardItemListView::slotSortRoleChanged(current, previous);
}
void KFileItemListView::triggerVisibleIndexRangeUpdate()
updateTimersInterval();
}
-void KFileItemListView::updateLayoutOfVisibleItems()
-{
- if (!model()) {
- return;
- }
-
- foreach (KItemListWidget* widget, visibleItemListWidgets()) {
- initializeItemListWidget(widget);
- }
- triggerVisibleIndexRangeUpdate();
-}
-
void KFileItemListView::updateTimersInterval()
{
if (!model()) {
QSet<QByteArray> roles = visibleRoles().toSet();
roles.insert("iconPixmap");
roles.insert("iconName");
- roles.insert("name");
+ roles.insert("text");
roles.insert("isDir");
if (supportsItemExpanding()) {
roles.insert("isExpanded");
{
const KItemListStyleOption& option = styleOption();
const int iconSize = option.iconSize;
- if (m_itemLayout == IconsLayout) {
+ if (itemLayout() == IconsLayout) {
const int maxIconWidth = itemSize().width() - 2 * option.padding;
return QSize(maxIconWidth, iconSize);
}
#include <libdolphin_export.h>
-#include <kitemviews/kitemlistview.h>
+#include <kitemviews/kstandarditemlistview.h>
class KFileItemModelRolesUpdater;
class QTimer;
* KItemListView::setWidgetCreator() and KItemListView::setGroupHeaderCreator()
* to apply customized generators.
*/
-class LIBDOLPHINPRIVATE_EXPORT KFileItemListView : public KItemListView
+class LIBDOLPHINPRIVATE_EXPORT KFileItemListView : public KStandardItemListView
{
Q_OBJECT
public:
- enum Layout
- {
- IconsLayout,
- CompactLayout,
- DetailsLayout
- };
-
KFileItemListView(QGraphicsWidget* parent = 0);
virtual ~KFileItemListView();
void setEnlargeSmallPreviews(bool enlarge);
bool enlargeSmallPreviews() const;
- void setItemLayout(Layout layout);
- Layout itemLayout() const;
-
/**
* Sets the list of enabled thumbnail plugins that are used for previews.
* Per default all plugins enabled in the KConfigGroup "PreviewSettings"
virtual QPixmap createDragPixmap(const QSet<int>& indexes) const;
protected:
- virtual void initializeItemListWidget(KItemListWidget* item);
- virtual bool itemSizeHintUpdateRequired(const QSet<QByteArray>& changedRoles) const;
+ virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const;
+ virtual KItemListGroupHeaderCreatorBase* defaultGroupHeaderCreator() const;
+ virtual void onPreviewsShownChanged(bool shown);
+ virtual void onItemLayoutChanged(ItemLayout current, ItemLayout previous);
virtual void onModelChanged(KItemModelBase* current, KItemModelBase* previous);
virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous);
void updateIconSize();
private:
- void updateLayoutOfVisibleItems();
void updateTimersInterval();
/**
QSize availableIconSize() const;
private:
- Layout m_itemLayout;
-
KFileItemModelRolesUpdater* m_modelRolesUpdater;
QTimer* m_updateVisibleIndexRangeTimer;
QTimer* m_updateIconSizeTimer;
#include "kfileitemlistwidget.h"
-#include "kfileitemlistview.h"
-#include "kfileitemmodel.h"
-
-#include <KIcon>
-#include <KIconEffect>
-#include <KIconLoader>
-#include <KLocale>
-#include <kratingpainter.h>
-#include <KStringHandler>
#include <KDebug>
+#include <KGlobal>
+#include <KLocale>
+#include <KIO/MetaData>
+#include <QDateTime>
-#include "private/kfileitemclipboard.h"
-#include "private/kitemlistroleeditor.h"
-#include "private/kpixmapmodifier.h"
-
-#include <QFontMetricsF>
-#include <QGraphicsScene>
-#include <QGraphicsSceneResizeEvent>
-#include <QGraphicsView>
-#include <QPainter>
-#include <QStyleOption>
-#include <QTextLayout>
-#include <QTextLine>
-
-// #define KFILEITEMLISTWIDGET_DEBUG
-
-KFileItemListWidget::KFileItemListWidget(QGraphicsItem* parent) :
- KItemListWidget(parent),
- m_isCut(false),
- m_isHidden(false),
- m_isExpandable(false),
- m_supportsItemExpanding(false),
- m_dirtyLayout(true),
- m_dirtyContent(true),
- m_dirtyContentRoles(),
- m_layout(IconsLayout),
- m_pixmapPos(),
- m_pixmap(),
- m_scaledPixmapSize(),
- m_iconRect(),
- m_hoverPixmap(),
- m_textInfo(),
- m_textRect(),
- m_sortedVisibleRoles(),
- m_expansionArea(),
- m_customTextColor(),
- m_additionalInfoTextColor(),
- m_overlay(),
- m_rating(),
- m_roleEditor(0)
-{
-}
-
-KFileItemListWidget::~KFileItemListWidget()
-{
- qDeleteAll(m_textInfo);
- m_textInfo.clear();
-
- delete m_roleEditor;
-}
-
-void KFileItemListWidget::setLayout(Layout layout)
-{
- if (m_layout != layout) {
- m_layout = layout;
- m_dirtyLayout = true;
- updateAdditionalInfoTextColor();
- update();
- }
-}
-
-KFileItemListWidget::Layout KFileItemListWidget::layout() const
-{
- return m_layout;
-}
-
-void KFileItemListWidget::setSupportsItemExpanding(bool supportsItemExpanding)
-{
- if (m_supportsItemExpanding != supportsItemExpanding) {
- m_supportsItemExpanding = supportsItemExpanding;
- m_dirtyLayout = true;
- update();
- }
-}
-
-bool KFileItemListWidget::supportsItemExpanding() const
-{
- return m_supportsItemExpanding;
-}
-
-void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
-
- KItemListWidget::paint(painter, option, widget);
-
- if (!m_expansionArea.isEmpty()) {
- drawSiblingsInformation(painter);
- }
-
- const KItemListStyleOption& itemListStyleOption = styleOption();
- if (isHovered()) {
- // Blend the unhovered and hovered pixmap if the hovering
- // animation is ongoing
- if (hoverOpacity() < 1.0) {
- drawPixmap(painter, m_pixmap);
- }
-
- const qreal opacity = painter->opacity();
- painter->setOpacity(hoverOpacity() * opacity);
- drawPixmap(painter, m_hoverPixmap);
- painter->setOpacity(opacity);
- } else {
- drawPixmap(painter, m_pixmap);
- }
-
- painter->setFont(itemListStyleOption.font);
- painter->setPen(textColor());
- const TextInfo* textInfo = m_textInfo.value("name");
- painter->drawStaticText(textInfo->pos, textInfo->staticText);
-
- bool clipAdditionalInfoBounds = false;
- if (m_supportsItemExpanding) {
- // Prevent a possible overlapping of the additional-information texts
- // with the icon. This can happen if the user has minimized the width
- // of the name-column to a very small value.
- const qreal minX = m_pixmapPos.x() + m_pixmap.width() + 4 * itemListStyleOption.padding;
- if (textInfo->pos.x() + columnWidth("name") > minX) {
- clipAdditionalInfoBounds = true;
- painter->save();
- painter->setClipRect(minX, 0, size().width() - minX, size().height(), Qt::IntersectClip);
- }
- }
-
- painter->setPen(m_additionalInfoTextColor);
- painter->setFont(itemListStyleOption.font);
-
- for (int i = 1; i < m_sortedVisibleRoles.count(); ++i) {
- const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles[i]);
- painter->drawStaticText(textInfo->pos, textInfo->staticText);
- }
-
- if (!m_rating.isNull()) {
- const TextInfo* ratingTextInfo = m_textInfo.value("rating");
- QPointF pos = ratingTextInfo->pos;
- const Qt::Alignment align = ratingTextInfo->staticText.textOption().alignment();
- if (align & Qt::AlignHCenter) {
- pos.rx() += (size().width() - m_rating.width()) / 2;
- }
- painter->drawPixmap(pos, m_rating);
- }
-
- if (clipAdditionalInfoBounds) {
- painter->restore();
- }
-
-#ifdef KFILEITEMLISTWIDGET_DEBUG
- painter->setBrush(Qt::NoBrush);
- painter->setPen(Qt::green);
- painter->drawRect(m_iconRect);
-
- painter->setPen(Qt::red);
- painter->drawText(QPointF(0, itemListStyleOption.fontMetrics.height()), QString::number(index()));
- painter->drawRect(rect());
-#endif
-}
-
-QRectF KFileItemListWidget::iconRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
- return m_iconRect;
-}
-
-QRectF KFileItemListWidget::textRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
- return m_textRect;
-}
-
-QRectF KFileItemListWidget::textFocusRect() const
-{
- // In the compact- and details-layout a larger textRect() is returned to be aligned
- // with the iconRect(). This is useful to have a larger selection/hover-area
- // when having a quite large icon size but only one line of text. Still the
- // focus rectangle should be shown as narrow as possible around the text.
-
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
-
- switch (m_layout) {
- case CompactLayout: {
- QRectF rect = m_textRect;
- const TextInfo* topText = m_textInfo.value(m_sortedVisibleRoles.first());
- const TextInfo* bottomText = m_textInfo.value(m_sortedVisibleRoles.last());
- rect.setTop(topText->pos.y());
- rect.setBottom(bottomText->pos.y() + bottomText->staticText.size().height());
- return rect;
- }
-
- case DetailsLayout: {
- QRectF rect = m_textRect;
- const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles.first());
- rect.setTop(textInfo->pos.y());
- rect.setBottom(textInfo->pos.y() + textInfo->staticText.size().height());
- return rect;
- }
-
- default:
- break;
- }
-
- return m_textRect;
-}
-
-QRectF KFileItemListWidget::expansionToggleRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
- return m_isExpandable ? m_expansionArea : QRectF();
-}
-
-QRectF KFileItemListWidget::selectionToggleRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
-
- const int iconHeight = styleOption().iconSize;
-
- int toggleSize = KIconLoader::SizeSmall;
- if (iconHeight >= KIconLoader::SizeEnormous) {
- toggleSize = KIconLoader::SizeMedium;
- } else if (iconHeight >= KIconLoader::SizeLarge) {
- toggleSize = KIconLoader::SizeSmallMedium;
- }
-
- QPointF pos = iconRect().topLeft();
-
- // If the selection toggle has a very small distance to the
- // widget borders, the size of the selection toggle will get
- // increased to prevent an accidental clicking of the item
- // when trying to hit the toggle.
- const int widgetHeight = size().height();
- const int widgetWidth = size().width();
- const int minMargin = 2;
-
- if (toggleSize + minMargin * 2 >= widgetHeight) {
- pos.rx() -= (widgetHeight - toggleSize) / 2;
- toggleSize = widgetHeight;
- pos.setY(0);
- }
- if (toggleSize + minMargin * 2 >= widgetWidth) {
- pos.ry() -= (widgetWidth - toggleSize) / 2;
- toggleSize = widgetWidth;
- pos.setX(0);
- }
-
- return QRectF(pos, QSizeF(toggleSize, toggleSize));
-}
-
-QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view)
-{
- const QHash<QByteArray, QVariant> values = view->model()->data(index);
- const KItemListStyleOption& option = view->styleOption();
- const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
-
- switch (static_cast<const KFileItemListView*>(view)->itemLayout()) {
- case IconsLayout: {
- const QString text = KStringHandler::preProcessWrap(values["name"].toString());
-
- const qreal itemWidth = view->itemSize().width();
- const qreal maxWidth = itemWidth - 2 * option.padding;
- QTextLine line;
-
- // Calculate the number of lines required for wrapping the name
- QTextOption textOption(Qt::AlignHCenter);
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
-
- qreal textHeight = 0;
- QTextLayout layout(text, option.font);
- layout.setTextOption(textOption);
- layout.beginLayout();
- while ((line = layout.createLine()).isValid()) {
- line.setLineWidth(maxWidth);
- line.naturalTextWidth();
- textHeight += line.height();
- }
- layout.endLayout();
-
- // Add one line for each additional information
- textHeight += additionalRolesCount * option.fontMetrics.lineSpacing();
-
- const qreal maxTextHeight = option.maxTextSize.height();
- if (maxTextHeight > 0 && textHeight > maxTextHeight) {
- textHeight = maxTextHeight;
- }
-
- return QSizeF(itemWidth, textHeight + option.iconSize + option.padding * 3);
- }
-
- 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);
- }
-
- qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth;
- const qreal maxWidth = option.maxTextSize.width();
- if (maxWidth > 0 && width > maxWidth) {
- width = maxWidth;
- }
- const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing());
- return QSizeF(width, height);
- }
-
- case DetailsLayout: {
- const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height());
- return QSizeF(-1, height);
- }
-
- default:
- Q_ASSERT(false);
- break;
- }
-
- return QSize();
-}
-
-qreal KFileItemListWidget::preferredRoleColumnWidth(const QByteArray& role,
- int index,
- const KItemListView* view)
-{
-
- const QHash<QByteArray, QVariant> values = view->model()->data(index);
- const KItemListStyleOption& option = view->styleOption();
-
- const QString text = KFileItemListWidget::roleText(role, values);
- qreal width = columnPadding(option);
-
- if (role == "rating") {
- width += preferredRatingSize(option).width();
- } else {
- width += 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()
-{
- m_dirtyLayout = true;
- m_dirtyContent = true;
-}
-
-void KFileItemListWidget::refreshCache()
-{
-}
-
-void KFileItemListWidget::setTextColor(const QColor& color)
-{
- if (color != m_customTextColor) {
- m_customTextColor = color;
- updateAdditionalInfoTextColor();
- update();
- }
-}
-
-QColor KFileItemListWidget::textColor() const
-{
- if (m_customTextColor.isValid() && !isSelected()) {
- return m_customTextColor;
- }
-
- const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive;
- const QPalette::ColorRole role = isSelected() ? QPalette::HighlightedText : QPalette::Text;
- return styleOption().palette.brush(group, role).color();
-}
-
-void KFileItemListWidget::setOverlay(const QPixmap& overlay)
-{
- m_overlay = overlay;
- m_dirtyContent = true;
- update();
-}
-
-QPixmap KFileItemListWidget::overlay() const
-{
- return m_overlay;
-}
-
-void KFileItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
- const QSet<QByteArray>& roles)
-{
- Q_UNUSED(current);
-
- m_dirtyContent = true;
-
- QSet<QByteArray> dirtyRoles;
- if (roles.isEmpty()) {
- dirtyRoles = visibleRoles().toSet();
- dirtyRoles.insert("iconPixmap");
- dirtyRoles.insert("iconName");
- } else {
- dirtyRoles = roles;
- }
-
- QSetIterator<QByteArray> it(dirtyRoles);
- while (it.hasNext()) {
- const QByteArray& role = it.next();
- m_dirtyContentRoles.insert(role);
- }
-}
-
-void KFileItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
- const QList<QByteArray>& previous)
-{
- Q_UNUSED(previous);
- m_sortedVisibleRoles = current;
- m_dirtyLayout = true;
-}
-
-void KFileItemListWidget::columnWidthChanged(const QByteArray& role,
- qreal current,
- qreal previous)
-{
- Q_UNUSED(role);
- Q_UNUSED(current);
- Q_UNUSED(previous);
- m_dirtyLayout = true;
-}
-
-void KFileItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
- const KItemListStyleOption& previous)
-{
- Q_UNUSED(current);
- Q_UNUSED(previous);
- updateAdditionalInfoTextColor();
- m_dirtyLayout = true;
-}
-
-void KFileItemListWidget::hoveredChanged(bool hovered)
-{
- Q_UNUSED(hovered);
- m_dirtyLayout = true;
-}
-
-void KFileItemListWidget::selectedChanged(bool selected)
-{
- Q_UNUSED(selected);
- updateAdditionalInfoTextColor();
-}
-
-void KFileItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous)
-{
- Q_UNUSED(current);
- Q_UNUSED(previous);
- m_dirtyLayout = true;
-}
-
-void KFileItemListWidget::editedRoleChanged(const QByteArray& current, const QByteArray& previous)
-{
- Q_UNUSED(previous);
-
- QGraphicsView* parent = scene()->views()[0];
- if (current.isEmpty() || !parent || current != "name") {
- if (m_roleEditor) {
- emit roleEditingCanceled(index(), current, data().value(current));
- m_roleEditor->deleteLater();
- m_roleEditor = 0;
- }
- return;
- }
-
- Q_ASSERT(!m_roleEditor);
-
- const TextInfo* textInfo = m_textInfo.value("name");
-
- m_roleEditor = new KItemListRoleEditor(parent);
- m_roleEditor->setIndex(index());
- m_roleEditor->setRole(current);
-
- const QString text = data().value(current).toString();
- m_roleEditor->setPlainText(text);
-
- QTextOption textOption = textInfo->staticText.textOption();
- m_roleEditor->document()->setDefaultTextOption(textOption);
-
- // Select the text without MIME-type extension
- int selectionLength = text.length();
-
- const QString extension = KMimeType::extractKnownExtension(text);
- if (!extension.isEmpty()) {
- selectionLength -= extension.length() + 1;
- }
-
- if (selectionLength > 0) {
- QTextCursor cursor = m_roleEditor->textCursor();
- cursor.movePosition(QTextCursor::StartOfBlock);
- cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selectionLength);
- m_roleEditor->setTextCursor(cursor);
- }
-
- connect(m_roleEditor, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)),
- this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
- connect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
- this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
-
- // Adjust the geometry of the editor
- QRectF rect = roleEditingRect(current);
- const int frameWidth = m_roleEditor->frameWidth();
- rect.adjust(-frameWidth, -frameWidth, frameWidth, frameWidth);
- rect.translate(pos());
- if (rect.right() > parent->width()) {
- rect.setWidth(parent->width() - rect.left());
- }
- if (rect.bottom() > parent->height()) {
- rect.setHeight(parent->height() - rect.top());
- }
- m_roleEditor->setGeometry(rect.toRect());
- m_roleEditor->show();
- m_roleEditor->setFocus();
-}
-
-void KFileItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
-{
- if (m_roleEditor) {
- setEditedRole(QByteArray());
- Q_ASSERT(!m_roleEditor);
- }
-
- KItemListWidget::resizeEvent(event);
-
- m_dirtyLayout = true;
-}
-
-void KFileItemListWidget::showEvent(QShowEvent* event)
-{
- KItemListWidget::showEvent(event);
-
- // Listen to changes of the clipboard to mark the item as cut/uncut
- KFileItemClipboard* clipboard = KFileItemClipboard::instance();
-
- const KUrl itemUrl = data().value("url").value<KUrl>();
- m_isCut = clipboard->isCut(itemUrl);
-
- connect(clipboard, SIGNAL(cutItemsChanged()),
- this, SLOT(slotCutItemsChanged()));
-}
-
-void KFileItemListWidget::hideEvent(QHideEvent* event)
-{
- disconnect(KFileItemClipboard::instance(), SIGNAL(cutItemsChanged()),
- this, SLOT(slotCutItemsChanged()));
-
- KItemListWidget::hideEvent(event);
-}
-
-void KFileItemListWidget::slotCutItemsChanged()
-{
- const KUrl itemUrl = data().value("url").value<KUrl>();
- const bool isCut = KFileItemClipboard::instance()->isCut(itemUrl);
- if (m_isCut != isCut) {
- m_isCut = isCut;
- m_pixmap = QPixmap();
- m_dirtyContent = true;
- update();
- }
-}
-
-void KFileItemListWidget::slotRoleEditingCanceled(int index,
- const QByteArray& role,
- const QVariant& value)
-{
- m_roleEditor->deleteLater();
- m_roleEditor = 0;
- emit roleEditingCanceled(index, role, value);
- setEditedRole(QByteArray());
-}
-
-void KFileItemListWidget::slotRoleEditingFinished(int index,
- const QByteArray& role,
- const QVariant& value)
-{
- m_roleEditor->deleteLater();
- m_roleEditor = 0;
- emit roleEditingFinished(index, role, value);
- setEditedRole(QByteArray());
-}
-
-void KFileItemListWidget::triggerCacheRefreshing()
-{
- if ((!m_dirtyContent && !m_dirtyLayout) || index() < 0) {
- return;
- }
-
- refreshCache();
-
- const QHash<QByteArray, QVariant> values = data();
- m_isExpandable = m_supportsItemExpanding && values["isExpandable"].toBool();
- m_isHidden = values["name"].toString().startsWith(QLatin1Char('.'));
-
- updateExpansionArea();
- updateTextsCache();
- updatePixmapCache();
-
- m_dirtyLayout = false;
- m_dirtyContent = false;
- m_dirtyContentRoles.clear();
-}
-
-void KFileItemListWidget::updateExpansionArea()
-{
- if (m_supportsItemExpanding) {
- const QHash<QByteArray, QVariant> values = data();
- Q_ASSERT(values.contains("expandedParentsCount"));
- const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
- if (expandedParentsCount >= 0) {
- const qreal widgetHeight = size().height();
- const qreal inc = (widgetHeight - KIconLoader::SizeSmall) / 2;
- const qreal x = expandedParentsCount * widgetHeight + inc;
- const qreal y = inc;
- m_expansionArea = QRectF(x, y, KIconLoader::SizeSmall, KIconLoader::SizeSmall);
- return;
- }
- }
-
- m_expansionArea = QRectF();
-}
-
-void KFileItemListWidget::updatePixmapCache()
-{
- // Precondition: Requires already updated m_textPos values to calculate
- // the remaining height when the alignment is vertical.
-
- const QSizeF widgetSize = size();
- const bool iconOnTop = (m_layout == IconsLayout);
- const KItemListStyleOption& option = styleOption();
- const qreal padding = option.padding;
-
- const int maxIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : option.iconSize;
- const int maxIconHeight = option.iconSize;
-
- const QHash<QByteArray, QVariant> values = data();
-
- bool updatePixmap = (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight);
- if (!updatePixmap && m_dirtyContent) {
- updatePixmap = m_dirtyContentRoles.isEmpty()
- || m_dirtyContentRoles.contains("iconPixmap")
- || m_dirtyContentRoles.contains("iconName")
- || m_dirtyContentRoles.contains("iconOverlays");
- }
-
- if (updatePixmap) {
- m_pixmap = values["iconPixmap"].value<QPixmap>();
- if (m_pixmap.isNull()) {
- // Use the icon that fits to the MIME-type
- QString iconName = values["iconName"].toString();
- if (iconName.isEmpty()) {
- // The icon-name has not been not resolved by KFileItemModelRolesUpdater,
- // use a generic icon as fallback
- iconName = QLatin1String("unknown");
- }
- m_pixmap = pixmapForIcon(iconName, maxIconHeight);
- } else if (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight) {
- // A custom pixmap has been applied. Assure that the pixmap
- // is scaled to the maximum available size.
- KPixmapModifier::scale(m_pixmap, QSize(maxIconWidth, maxIconHeight));
- }
-
- const QStringList overlays = values["iconOverlays"].toStringList();
-
- // Strangely KFileItem::overlays() returns empty string-values, so
- // we need to check first whether an overlay must be drawn at all.
- // It is more efficient to do it here, as KIconLoader::drawOverlays()
- // assumes that an overlay will be drawn and has some additional
- // setup time.
- foreach (const QString& overlay, overlays) {
- if (!overlay.isEmpty()) {
- // There is at least one overlay, draw all overlays above m_pixmap
- // and cancel the check
- KIconLoader::global()->drawOverlays(overlays, m_pixmap, KIconLoader::Desktop);
- break;
- }
- }
-
- if (m_isCut) {
- applyCutEffect(m_pixmap);
- }
-
- if (m_isHidden) {
- applyHiddenEffect(m_pixmap);
- }
- }
-
- if (!m_overlay.isNull()) {
- QPainter painter(&m_pixmap);
- painter.drawPixmap(0, m_pixmap.height() - m_overlay.height(), m_overlay);
- }
-
- int scaledIconSize = 0;
- if (iconOnTop) {
- const TextInfo* textInfo = m_textInfo.value("name");
- scaledIconSize = static_cast<int>(textInfo->pos.y() - 2 * padding);
- } else {
- const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1;
- const qreal requiredTextHeight = textRowsCount * option.fontMetrics.height();
- scaledIconSize = (requiredTextHeight < maxIconHeight) ?
- widgetSize.height() - 2 * padding : maxIconHeight;
- }
-
- const int maxScaledIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : scaledIconSize;
- const int maxScaledIconHeight = scaledIconSize;
-
- m_scaledPixmapSize = m_pixmap.size();
- m_scaledPixmapSize.scale(maxScaledIconWidth, maxScaledIconHeight, Qt::KeepAspectRatio);
-
- if (iconOnTop) {
- // Center horizontally and align on bottom within the icon-area
- m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2);
- m_pixmapPos.setY(padding + scaledIconSize - m_scaledPixmapSize.height());
- } else {
- // Center horizontally and vertically within the icon-area
- const TextInfo* textInfo = m_textInfo.value("name");
- m_pixmapPos.setX(textInfo->pos.x() - 2 * padding
- - (scaledIconSize + m_scaledPixmapSize.width()) / 2);
- m_pixmapPos.setY(padding
- + (scaledIconSize - m_scaledPixmapSize.height()) / 2);
- }
-
- m_iconRect = QRectF(m_pixmapPos, QSizeF(m_scaledPixmapSize));
-
- // Prepare the pixmap that is used when the item gets hovered
- if (isHovered()) {
- m_hoverPixmap = m_pixmap;
- KIconEffect* effect = KIconLoader::global()->iconEffect();
- // In the KIconLoader terminology, active = hover.
- if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
- m_hoverPixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState);
- } else {
- m_hoverPixmap = m_pixmap;
- }
- } else if (hoverOpacity() <= 0.0) {
- // No hover animation is ongoing. Clear m_hoverPixmap to save memory.
- m_hoverPixmap = QPixmap();
- }
-}
-
-void KFileItemListWidget::updateTextsCache()
-{
- QTextOption textOption;
- switch (m_layout) {
- case IconsLayout:
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- textOption.setAlignment(Qt::AlignHCenter);
- break;
- case CompactLayout:
- case DetailsLayout:
- textOption.setAlignment(Qt::AlignLeft);
- textOption.setWrapMode(QTextOption::NoWrap);
- break;
- default:
- Q_ASSERT(false);
- break;
- }
-
- qDeleteAll(m_textInfo);
- m_textInfo.clear();
- for (int i = 0; i < m_sortedVisibleRoles.count(); ++i) {
- TextInfo* textInfo = new TextInfo();
- textInfo->staticText.setTextFormat(Qt::PlainText);
- textInfo->staticText.setPerformanceHint(QStaticText::AggressiveCaching);
- textInfo->staticText.setTextOption(textOption);
- m_textInfo.insert(m_sortedVisibleRoles[i], textInfo);
- }
-
- switch (m_layout) {
- case IconsLayout: updateIconsLayoutTextCache(); break;
- case CompactLayout: updateCompactLayoutTextCache(); break;
- case DetailsLayout: updateDetailsLayoutTextCache(); break;
- default: Q_ASSERT(false); break;
- }
-
- const TextInfo* ratingTextInfo = m_textInfo.value("rating");
- if (ratingTextInfo) {
- // The text of the rating-role has been set to empty to get
- // replaced by a rating-image showing the rating as stars.
- const KItemListStyleOption& option = styleOption();
- QSizeF ratingSize = preferredRatingSize(option);
-
- const qreal availableWidth = (m_layout == DetailsLayout)
- ? columnWidth("rating") - columnPadding(option)
- : m_textRect.width();
- if (ratingSize.width() > availableWidth) {
- ratingSize.rwidth() = availableWidth;
- }
- m_rating = QPixmap(ratingSize.toSize());
- m_rating.fill(Qt::transparent);
-
- QPainter painter(&m_rating);
- const QRect rect(0, 0, m_rating.width(), m_rating.height());
- const int rating = data().value("rating").toInt();
- KRatingPainter::paintRating(&painter, rect, Qt::AlignJustify | Qt::AlignVCenter, rating);
- } else if (!m_rating.isNull()) {
- m_rating = QPixmap();
- }
-}
-
-void KFileItemListWidget::updateIconsLayoutTextCache()
-{
- // +------+
- // | Icon |
- // +------+
- //
- // Name role that
- // might get wrapped above
- // several lines.
- // Additional role 1
- // Additional role 2
-
- const QHash<QByteArray, QVariant> values = data();
-
- const KItemListStyleOption& option = styleOption();
- const qreal padding = option.padding;
- const qreal maxWidth = size().width() - 2 * padding;
- const qreal widgetHeight = size().height();
- const qreal lineSpacing = option.fontMetrics.lineSpacing();
-
- // Initialize properties for the "name" role. It will be used as anchor
- // for initializing the position of the other roles.
- TextInfo* nameTextInfo = m_textInfo.value("name");
- const QString nameText = KStringHandler::preProcessWrap(values["name"].toString());
- nameTextInfo->staticText.setText(nameText);
-
- // Calculate the number of lines required for the name and the required width
- qreal nameWidth = 0;
- qreal nameHeight = 0;
- QTextLine line;
-
- const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
- const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount;
-
- QTextLayout layout(nameTextInfo->staticText.text(), option.font);
- layout.setTextOption(nameTextInfo->staticText.textOption());
- layout.beginLayout();
- int nameLineIndex = 0;
- while ((line = layout.createLine()).isValid()) {
- line.setLineWidth(maxWidth);
- nameWidth = qMax(nameWidth, line.naturalTextWidth());
- nameHeight += line.height();
-
- ++nameLineIndex;
- if (nameLineIndex == maxNameLines) {
- // The maximum number of textlines has been reached. If this is
- // the case provide an elided text if necessary.
- const int textLength = line.textStart() + line.textLength();
- if (textLength < nameText.length()) {
- // Elide the last line of the text
- QString lastTextLine = nameText.mid(line.textStart(), line.textLength());
- lastTextLine = option.fontMetrics.elidedText(lastTextLine,
- Qt::ElideRight,
- line.naturalTextWidth() - 1);
- const QString elidedText = nameText.left(line.textStart()) + lastTextLine;
- nameTextInfo->staticText.setText(elidedText);
- }
- break;
- }
- }
- layout.endLayout();
-
- // Use one line for each additional information
- nameTextInfo->staticText.setTextWidth(maxWidth);
- nameTextInfo->pos = QPointF(padding, widgetHeight -
- nameHeight -
- additionalRolesCount * lineSpacing -
- padding);
- m_textRect = QRectF(padding + (maxWidth - nameWidth) / 2,
- nameTextInfo->pos.y(),
- nameWidth,
- nameHeight);
-
- // Calculate the position for each additional information
- qreal y = nameTextInfo->pos.y() + nameHeight;
- foreach (const QByteArray& role, m_sortedVisibleRoles) {
- if (role == "name") {
- continue;
- }
-
- const QString text = roleText(role, values);
- TextInfo* textInfo = m_textInfo.value(role);
- textInfo->staticText.setText(text);
-
- qreal requiredWidth = 0;
-
- QTextLayout layout(text, option.font);
- QTextOption textOption;
- textOption.setWrapMode(QTextOption::NoWrap);
- layout.setTextOption(textOption);
-
- layout.beginLayout();
- QTextLine textLine = layout.createLine();
- if (textLine.isValid()) {
- textLine.setLineWidth(maxWidth);
- requiredWidth = textLine.naturalTextWidth();
- if (requiredWidth > maxWidth) {
- const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
- textInfo->staticText.setText(elidedText);
- requiredWidth = option.fontMetrics.width(elidedText);
- }
- }
- layout.endLayout();
-
- textInfo->pos = QPointF(padding, y);
- textInfo->staticText.setTextWidth(maxWidth);
-
- const QRectF textRect(padding + (maxWidth - requiredWidth) / 2, y, requiredWidth, lineSpacing);
- m_textRect |= textRect;
-
- y += lineSpacing;
- }
-
- // Add a padding to the text rectangle
- m_textRect.adjust(-padding, -padding, padding, padding);
-}
-
-void KFileItemListWidget::updateCompactLayoutTextCache()
-{
- // +------+ Name role
- // | Icon | Additional role 1
- // +------+ Additional role 2
-
- const QHash<QByteArray, QVariant> values = data();
-
- const KItemListStyleOption& option = styleOption();
- const qreal widgetHeight = size().height();
- const qreal lineSpacing = option.fontMetrics.lineSpacing();
- const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * lineSpacing;
- const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.padding : option.iconSize;
-
- qreal maximumRequiredTextWidth = 0;
- const qreal x = option.padding * 3 + scaledIconSize;
- qreal y = qRound((widgetHeight - textLinesHeight) / 2);
- const qreal maxWidth = size().width() - x - option.padding;
- foreach (const QByteArray& role, m_sortedVisibleRoles) {
- const QString text = roleText(role, values);
- TextInfo* textInfo = m_textInfo.value(role);
- textInfo->staticText.setText(text);
-
- qreal requiredWidth = option.fontMetrics.width(text);
- if (requiredWidth > maxWidth) {
- requiredWidth = maxWidth;
- const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
- textInfo->staticText.setText(elidedText);
- }
-
- textInfo->pos = QPointF(x, y);
- textInfo->staticText.setTextWidth(maxWidth);
-
- maximumRequiredTextWidth = qMax(maximumRequiredTextWidth, requiredWidth);
-
- y += lineSpacing;
- }
-
- m_textRect = QRectF(x - option.padding, 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight);
-}
-
-void KFileItemListWidget::updateDetailsLayoutTextCache()
-{
- // Precondition: Requires already updated m_expansionArea
- // to determine the left position.
-
- // +------+
- // | Icon | Name role Additional role 1 Additional role 2
- // +------+
- m_textRect = QRectF();
-
- const KItemListStyleOption& option = styleOption();
- const QHash<QByteArray, QVariant> values = data();
-
- const qreal widgetHeight = size().height();
- const int scaledIconSize = widgetHeight - 2 * option.padding;
- const int fontHeight = option.fontMetrics.height();
-
- const qreal columnWidthInc = columnPadding(option);
- qreal firstColumnInc = scaledIconSize;
- if (m_supportsItemExpanding) {
- firstColumnInc += (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2;
- } else {
- firstColumnInc += option.padding;
- }
-
- qreal x = firstColumnInc;
- const qreal y = qMax(qreal(option.padding), (widgetHeight - fontHeight) / 2);
-
- foreach (const QByteArray& role, m_sortedVisibleRoles) {
- const RoleType type = roleType(role);
-
- QString text = roleText(role, values);
-
- // Elide the text in case it does not fit into the available column-width
- qreal requiredWidth = option.fontMetrics.width(text);
- const qreal roleWidth = columnWidth(role);
- qreal availableTextWidth = roleWidth - columnWidthInc;
- if (type == Name) {
- availableTextWidth -= firstColumnInc;
- }
-
- if (requiredWidth > availableTextWidth) {
- text = option.fontMetrics.elidedText(text, Qt::ElideRight, availableTextWidth);
- requiredWidth = option.fontMetrics.width(text);
- }
-
- TextInfo* textInfo = m_textInfo.value(role);
- textInfo->staticText.setText(text);
- textInfo->pos = QPointF(x + columnWidthInc / 2, y);
- x += roleWidth;
-
- switch (type) {
- case Name: {
- const qreal textWidth = option.extendedSelectionRegion
- ? size().width() - textInfo->pos.x()
- : requiredWidth + 2 * option.padding;
- m_textRect = QRectF(textInfo->pos.x() - option.padding, 0,
- textWidth, size().height());
-
- // The column after the name should always be aligned on the same x-position independent
- // from the expansion-level shown in the name column
- x -= firstColumnInc;
- break;
- }
- case Size:
- // The values for the size should be right aligned
- textInfo->pos.rx() += roleWidth - requiredWidth - columnWidthInc;
- break;
-
- default:
- break;
- }
- }
-}
-
-void KFileItemListWidget::updateAdditionalInfoTextColor()
-{
- QColor c1;
- if (m_customTextColor.isValid()) {
- c1 = m_customTextColor;
- } else if (isSelected() && m_layout != DetailsLayout) {
- c1 = styleOption().palette.highlightedText().color();
- } else {
- c1 = styleOption().palette.text().color();
- }
-
- // For the color of the additional info the inactive text color
- // is not used as this might lead to unreadable text for some color schemes. Instead
- // the text color c1 is slightly mixed with the background color.
- const QColor c2 = styleOption().palette.base().color();
- const int p1 = 70;
- const int p2 = 100 - p1;
- m_additionalInfoTextColor = QColor((c1.red() * p1 + c2.red() * p2) / 100,
- (c1.green() * p1 + c2.green() * p2) / 100,
- (c1.blue() * p1 + c2.blue() * p2) / 100);
-}
-
-void KFileItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap)
-{
- if (m_scaledPixmapSize != pixmap.size()) {
- QPixmap scaledPixmap = pixmap;
- KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize);
- painter->drawPixmap(m_pixmapPos, scaledPixmap);
-
-#ifdef KFILEITEMLISTWIDGET_DEBUG
- painter->setPen(Qt::blue);
- painter->drawRect(QRectF(m_pixmapPos, QSizeF(m_scaledPixmapSize)));
-#endif
- } else {
- painter->drawPixmap(m_pixmapPos, pixmap);
- }
-}
-
-void KFileItemListWidget::drawSiblingsInformation(QPainter* painter)
-{
- const int siblingSize = size().height();
- const int x = (m_expansionArea.left() + m_expansionArea.right() - siblingSize) / 2;
- QRect siblingRect(x, 0, siblingSize, siblingSize);
-
- QStyleOption option;
- bool isItemSibling = true;
-
- const QBitArray siblings = siblingsInformation();
- for (int i = siblings.count() - 1; i >= 0; --i) {
- option.rect = siblingRect;
- option.state = siblings.at(i) ? QStyle::State_Sibling : QStyle::State_None;
-
- if (isItemSibling) {
- option.state |= QStyle::State_Item;
- if (m_isExpandable) {
- option.state |= QStyle::State_Children;
- }
- if (data()["isExpanded"].toBool()) {
- option.state |= QStyle::State_Open;
- }
- isItemSibling = false;
- }
-
- style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter);
-
- siblingRect.translate(-siblingRect.width(), 0);
- }
-}
-
-QRectF KFileItemListWidget::roleEditingRect(const QByteArray& role) const
-{
- const TextInfo* textInfo = m_textInfo.value(role);
- if (!textInfo) {
- return QRectF();
- }
-
- QRectF rect(textInfo->pos, textInfo->staticText.size());
- if (m_layout == DetailsLayout) {
- rect.setWidth(columnWidth(role) - rect.x());
- }
-
- return rect;
-}
-
-QPixmap KFileItemListWidget::pixmapForIcon(const QString& name, int size)
-{
- const KIcon icon(name);
-
- int requestedSize;
- if (size <= KIconLoader::SizeSmall) {
- requestedSize = KIconLoader::SizeSmall;
- } else if (size <= KIconLoader::SizeSmallMedium) {
- requestedSize = KIconLoader::SizeSmallMedium;
- } else if (size <= KIconLoader::SizeMedium) {
- requestedSize = KIconLoader::SizeMedium;
- } else if (size <= KIconLoader::SizeLarge) {
- requestedSize = KIconLoader::SizeLarge;
- } else if (size <= KIconLoader::SizeHuge) {
- requestedSize = KIconLoader::SizeHuge;
- } else if (size <= KIconLoader::SizeEnormous) {
- requestedSize = KIconLoader::SizeEnormous;
- } else if (size <= KIconLoader::SizeEnormous * 2) {
- requestedSize = KIconLoader::SizeEnormous * 2;
- } else {
- requestedSize = size;
- }
-
- QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
- if (requestedSize != size) {
- KPixmapModifier::scale(pixmap, QSize(size, size));
- }
-
- 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)
+KFileItemListWidgetInformant::KFileItemListWidgetInformant() :
+ KStandardItemListWidgetInformant()
{
- KIconEffect::semiTransparent(pixmap);
}
-KFileItemListWidget::RoleType KFileItemListWidget::roleType(const QByteArray& role)
+KFileItemListWidgetInformant::~KFileItemListWidgetInformant()
{
- static QHash<QByteArray, RoleType> rolesHash;
- if (rolesHash.isEmpty()) {
- rolesHash.insert("name", Name);
- rolesHash.insert("size", Size);
- rolesHash.insert("date", Date);
- rolesHash.insert("rating", Rating);
- }
-
- return rolesHash.value(role, Generic);
}
-QString KFileItemListWidget::roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values)
+QString KFileItemListWidgetInformant::roleText(const QByteArray& role,
+ const QHash<QByteArray, QVariant>& values) const
{
QString text;
const QVariant roleValue = values.value(role);
- switch (roleType(role)) {
- case Size: {
+ // Implementation note: In case if more roles require a custom handling
+ // use a hash + switch for a linear runtime.
+
+ if (role == "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.
const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
text = KGlobal::locale()->formatByteSize(size);
}
- break;
- }
-
- case Date: {
+ } else if (role == "date") {
const QDateTime dateTime = roleValue.toDateTime();
text = KGlobal::locale()->formatDateTime(dateTime);
- break;
+ } else {
+ text = KStandardItemListWidgetInformant::roleText(role, values);
}
- case Rating:
- // Always use an empty text, as the rating is shown by the image m_rating.
- break;
-
- case Name:
- case Generic:
- text = roleValue.toString();
- break;
+ return text;
+}
- default:
- Q_ASSERT(false);
- break;
- }
+KFileItemListWidget::KFileItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) :
+ KStandardItemListWidget(informant, parent)
+{
+}
- return text;
+KFileItemListWidget::~KFileItemListWidget()
+{
}
-QSizeF KFileItemListWidget::preferredRatingSize(const KItemListStyleOption& option)
+KItemListWidgetInformant* KFileItemListWidget::createInformant()
{
- const qreal height = option.fontMetrics.ascent();
- return QSizeF(height * 5, height);
+ return new KFileItemListWidgetInformant();
}
-qreal KFileItemListWidget::columnPadding(const KItemListStyleOption& option)
+bool KFileItemListWidget::isRoleRightAligned(const QByteArray& role) const
{
- return option.padding * 6;
+ return role == "size";
}
#include "kfileitemlistwidget.moc"
#include <libdolphin_export.h>
-#include <kitemviews/kitemlistwidget.h>
+#include <kitemviews/kstandarditemlistwidget.h>
-#include <QPixmap>
-#include <QPointF>
-#include <QStaticText>
+class LIBDOLPHINPRIVATE_EXPORT KFileItemListWidgetInformant : public KStandardItemListWidgetInformant
+{
+public:
+ KFileItemListWidgetInformant();
+ virtual ~KFileItemListWidgetInformant();
-class KItemListRoleEditor;
-class KItemListStyleOption;
-class KItemListView;
+protected:
+ virtual QString roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values) const;
+};
-class LIBDOLPHINPRIVATE_EXPORT KFileItemListWidget : public KItemListWidget
+class LIBDOLPHINPRIVATE_EXPORT KFileItemListWidget : public KStandardItemListWidget
{
Q_OBJECT
public:
- enum Layout
- {
- IconsLayout,
- CompactLayout,
- DetailsLayout
- };
-
- KFileItemListWidget(QGraphicsItem* parent);
+ KFileItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent);
virtual ~KFileItemListWidget();
- void setLayout(Layout layout);
- Layout layout() const;
-
- void setSupportsItemExpanding(bool supportsItemExpanding);
- bool supportsItemExpanding() const;
-
- virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
-
- virtual QRectF iconRect() const;
- virtual QRectF textRect() const;
- virtual QRectF textFocusRect() const;
- virtual QRectF expansionToggleRect() const;
- virtual QRectF selectionToggleRect() const;
-
- /**
- * Implementation of KItemListWidgetCreatorBase::itemSizeHint() when
- * using the KItemListWidgetCreator-template.
- *
- * @see KItemListView
- */
- 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);
+ static KItemListWidgetInformant* createInformant();
protected:
- /**
- * Invalidates the cache which results in calling KFileItemListWidget::refreshCache() as
- * soon as the item need to gets repainted.
- */
- void invalidateCache();
-
- /**
- * Is called if the cache got invalidated by KFileItemListWidget::invalidateCache().
- * The default implementation is empty.
- */
- virtual void refreshCache();
-
- void setTextColor(const QColor& color);
- QColor textColor() const;
-
- void setOverlay(const QPixmap& overlay);
- QPixmap overlay() const;
-
- virtual void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>());
- virtual void visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous);
- virtual void columnWidthChanged(const QByteArray& role, qreal current, qreal previous);
- virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
- virtual void hoveredChanged(bool hovered);
- virtual void selectedChanged(bool selected);
- virtual void siblingsInformationChanged(const QBitArray& current, const QBitArray& previous);
- virtual void editedRoleChanged(const QByteArray& current, const QByteArray& previous);
- virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
- virtual void showEvent(QShowEvent* event);
- virtual void hideEvent(QHideEvent* event);
-
-private slots:
- void slotCutItemsChanged();
- void slotRoleEditingCanceled(int index, const QByteArray& role, const QVariant& value);
- void slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value);
-
-private:
- /**
- * Typedefinitions for roles that require a special handling
- * and must be accessible in a fast way. The mapping of a
- * QByteArray role to the type is done by KFileItemListWidget::roleType().
- */
- enum RoleType {
- Name,
- Size,
- Date,
- Rating,
- Generic // Mandatory last entry
- };
-
- void triggerCacheRefreshing();
- void updateExpansionArea();
- void updatePixmapCache();
-
- void updateTextsCache();
- void updateIconsLayoutTextCache();
- void updateCompactLayoutTextCache();
- void updateDetailsLayoutTextCache();
-
- void updateAdditionalInfoTextColor();
-
- void drawPixmap(QPainter* painter, const QPixmap& pixmap);
- void drawSiblingsInformation(QPainter* painter);
-
- QRectF roleEditingRect(const QByteArray &role) const;
-
- static QPixmap pixmapForIcon(const QString& name, int size);
- static void applyCutEffect(QPixmap& pixmap);
- static void applyHiddenEffect(QPixmap& pixmap);
- static RoleType roleType(const QByteArray& role);
-
- /**
- * @return Preferred size of the rating-image based on the given
- * style-option. The height of the font is taken as
- * reference.
- */
- static QSizeF preferredRatingSize(const KItemListStyleOption& option);
-
- /**
- * @return Horizontal padding in pixels that is added to the required width of
- * a column to display the content.
- */
- static qreal columnPadding(const KItemListStyleOption& option);
-
- /**
- * @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;
- bool m_isHidden;
- bool m_isExpandable;
- bool m_supportsItemExpanding;
-
- bool m_dirtyLayout;
- bool m_dirtyContent;
- QSet<QByteArray> m_dirtyContentRoles;
-
- Layout m_layout;
- QPointF m_pixmapPos;
- QPixmap m_pixmap;
- QSize m_scaledPixmapSize;
-
- QRectF m_iconRect; // Cache for KItemListWidget::iconRect()
- QPixmap m_hoverPixmap; // Cache for modified m_pixmap when hovering the item
-
- struct TextInfo
- {
- QPointF pos;
- QStaticText staticText;
- };
- QHash<QByteArray, TextInfo*> m_textInfo;
-
- QRectF m_textRect;
-
- QList<QByteArray> m_sortedVisibleRoles;
-
- QRectF m_expansionArea;
-
- QColor m_customTextColor;
- QColor m_additionalInfoTextColor;
-
- QPixmap m_overlay;
- QPixmap m_rating;
-
- KItemListRoleEditor* m_roleEditor;
+ virtual bool isRoleRightAligned(const QByteArray& role) const;
};
#endif
// #define KFILEITEMMODEL_DEBUG
KFileItemModel::KFileItemModel(QObject* parent) :
- KItemModelBase("name", parent),
+ KItemModelBase("text", parent),
m_dirLister(0),
m_naturalSorting(KGlobalSettings::naturalSorting()),
m_sortDirsFirst(true),
resetRoles();
m_requestRole[NameRole] = true;
m_requestRole[IsDirRole] = true;
- m_roles.insert("name");
+ m_roles.insert("text");
m_roles.insert("isDir");
// For slow KIO-slaves like used for searching it makes sense to show results periodically even
{
startFromIndex = qMax(0, startFromIndex);
for (int i = startFromIndex; i < count(); ++i) {
- if (data(i)["name"].toString().startsWith(text, Qt::CaseInsensitive)) {
+ if (data(i)["text"].toString().startsWith(text, Qt::CaseInsensitive)) {
return i;
}
}
for (int i = 0; i < startFromIndex; ++i) {
- if (data(i)["name"].toString().startsWith(text, Qt::CaseInsensitive)) {
+ if (data(i)["text"].toString().startsWith(text, Qt::CaseInsensitive)) {
return i;
}
}
}
if (m_requestRole[NameRole]) {
- data.insert("name", item.text());
+ data.insert("text", item.text());
}
if (m_requestRole[SizeRole]) {
continue;
}
- const QString name = m_itemData.at(i)->values.value("name").toString();
+ const QString name = m_itemData.at(i)->values.value("text").toString();
// Use the first character of the name as group indication
QChar newFirstChar = name.at(0).toUpper();
static const RoleInfoMap rolesInfoMap[] = {
// | role | roleType | role translation | group translation | requires Nepomuk | requires indexer
{ 0, NoRole, 0, 0, 0, 0, false, false },
- { "name", NameRole, I18N_NOOP2_NOSTRIP("@label", "Name"), 0, 0, false, false },
+ { "text", NameRole, I18N_NOOP2_NOSTRIP("@label", "Name"), 0, 0, false, false },
{ "size", SizeRole, I18N_NOOP2_NOSTRIP("@label", "Size"), 0, 0, false, false },
{ "date", DateRole, I18N_NOOP2_NOSTRIP("@label", "Date"), 0, 0, false, false },
{ "type", TypeRole, I18N_NOOP2_NOSTRIP("@label", "Type"), 0, 0, false, false },
virtual bool supportsDropping(int index) const;
/** @reimp */
- virtual QString roleDescription(const QByteArray& typeForRole) const;
+ virtual QString roleDescription(const QByteArray& role) const;
/** @reimp */
virtual QList<QPair<int, QVariant> > groups() const;
event->ignore();
}
-
-
KItemListContainer::KItemListContainer(KItemListController* controller, QWidget* parent) :
QAbstractScrollArea(parent),
m_controller(controller),
{
Q_ASSERT(controller);
controller->setParent(this);
- initialize();
-}
-KItemListContainer::KItemListContainer(QWidget* parent) :
- QAbstractScrollArea(parent),
- m_controller(0),
- m_horizontalSmoothScroller(0),
- m_verticalSmoothScroller(0)
-{
- initialize();
+ QGraphicsView* graphicsView = new KItemListContainerViewport(new QGraphicsScene(this), this);
+ setViewport(graphicsView);
+
+ m_horizontalSmoothScroller = new KItemListSmoothScroller(horizontalScrollBar(), this);
+ m_verticalSmoothScroller = new KItemListSmoothScroller(verticalScrollBar(), this);
+
+ if (controller->model()) {
+ slotModelChanged(controller->model(), 0);
+ }
+ if (controller->view()) {
+ slotViewChanged(controller->view(), 0);
+ }
+
+ connect(controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)),
+ this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
+ connect(controller, SIGNAL(viewChanged(KItemListView*,KItemListView*)),
+ this, SLOT(slotViewChanged(KItemListView*,KItemListView*)));
}
KItemListContainer::~KItemListContainer()
{
+ // Don't rely on the QObject-order to delete the controller, otherwise
+ // the QGraphicsScene might get deleted before the view.
+ delete m_controller;
+ m_controller = 0;
}
KItemListController* KItemListContainer::controller() const
return m_controller;
}
+void KItemListContainer::setEnabledFrame(bool enable)
+{
+ QGraphicsView* graphicsView = qobject_cast<QGraphicsView*>(viewport());
+ if (enable) {
+ setFrameShape(QFrame::StyledPanel);
+ graphicsView->setPalette(palette());
+ graphicsView->viewport()->setAutoFillBackground(true);
+ } else {
+ setFrameShape(QFrame::NoFrame);
+ // Make the background of the container transparent and apply the window-text color
+ // to the text color, so that enough contrast is given for all color
+ // schemes
+ QPalette p = graphicsView->palette();
+ p.setColor(QPalette::Active, QPalette::Text, p.color(QPalette::Active, QPalette::WindowText));
+ p.setColor(QPalette::Inactive, QPalette::Text, p.color(QPalette::Inactive, QPalette::WindowText));
+ p.setColor(QPalette::Disabled, QPalette::Text, p.color(QPalette::Disabled, QPalette::WindowText));
+ graphicsView->setPalette(p);
+ graphicsView->viewport()->setAutoFillBackground(false);
+ }
+}
+
+bool KItemListContainer::enabledFrame() const
+{
+ const QGraphicsView* graphicsView = qobject_cast<QGraphicsView*>(viewport());
+ return graphicsView->autoFillBackground();
+}
+
void KItemListContainer::keyPressEvent(QKeyEvent* event)
{
// TODO: We should find a better way to handle the key press events in the view.
}
}
-void KItemListContainer::initialize()
-{
- if (m_controller) {
- if (m_controller->model()) {
- slotModelChanged(m_controller->model(), 0);
- }
- if (m_controller->view()) {
- slotViewChanged(m_controller->view(), 0);
- }
- } else {
- m_controller = new KItemListController(this);
- }
-
- connect(m_controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)),
- this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
- connect(m_controller, SIGNAL(viewChanged(KItemListView*,KItemListView*)),
- this, SLOT(slotViewChanged(KItemListView*,KItemListView*)));
-
- QGraphicsView* graphicsView = new KItemListContainerViewport(new QGraphicsScene(this), this);
- setViewport(graphicsView);
-
- m_horizontalSmoothScroller = new KItemListSmoothScroller(horizontalScrollBar(), this);
- m_verticalSmoothScroller = new KItemListSmoothScroller(verticalScrollBar(), this);
-}
-
#include "kitemlistcontainer.moc"
/**
* @brief Provides a QWidget based scrolling view for a KItemListController.
*
+ * The model and view are maintained by the KItemListController.
+ *
* @see KItemListController
*/
class LIBDOLPHINPRIVATE_EXPORT KItemListContainer : public QAbstractScrollArea
Q_OBJECT
public:
+ /**
+ * @param controller Controller that maintains the model and the view.
+ * The KItemListContainer takes ownership of the controller
+ * (the parent will be set to the KItemListContainer).
+ * @param parent Optional parent widget.
+ */
explicit KItemListContainer(KItemListController* controller, QWidget* parent = 0);
- KItemListContainer(QWidget* parent = 0);
virtual ~KItemListContainer();
-
KItemListController* controller() const;
+ void setEnabledFrame(bool enable);
+ bool enabledFrame() const;
+
protected:
virtual void keyPressEvent(QKeyEvent* event);
virtual void showEvent(QShowEvent* event);
void updateItemOffsetScrollBar();
private:
- void initialize();
void updateGeometries();
void updateSmoothScrollers(Qt::Orientation orientation);
#include <QMimeData>
#include <QTimer>
-KItemListController::KItemListController(QObject* parent) :
+KItemListController::KItemListController(KItemModelBase* model, KItemListView* view, QObject* parent) :
QObject(parent),
m_singleClickActivation(KGlobalSettings::singleClick()),
m_selectionTogglePressed(false),
m_autoActivationTimer->setSingleShot(true);
m_autoActivationTimer->setInterval(-1);
connect(m_autoActivationTimer, SIGNAL(timeout()), this, SLOT(slotAutoActivationTimeout()));
+
+ setModel(model);
+ setView(view);
}
KItemListController::~KItemListController()
{
+ setView(0);
+ delete m_view;
+ m_view = 0;
+
+ setModel(0);
+ delete m_model;
+ m_model = 0;
}
void KItemListController::setModel(KItemModelBase* model)
KItemModelBase* oldModel = m_model;
m_model = model;
+ if (m_model) {
+ m_model->setParent(this);
+ }
if (m_view) {
m_view->setModel(m_model);
m_view->setController(this);
m_view->setModel(m_model);
connect(m_view, SIGNAL(scrollOffsetChanged(qreal,qreal)), this, SLOT(slotViewScrollOffsetChanged(qreal,qreal)));
+ updateExtendedSelectionRegion();
}
emit viewChanged(m_view, oldView);
void KItemListController::setSelectionBehavior(SelectionBehavior behavior)
{
m_selectionBehavior = behavior;
+ updateExtendedSelectionRegion();
}
KItemListController::SelectionBehavior KItemListController::selectionBehavior() const
return 0;
}
+void KItemListController::updateExtendedSelectionRegion()
+{
+ if (m_view) {
+ const bool extend = (m_selectionBehavior != MultiSelection);
+ KItemListStyleOption option = m_view->styleOption();
+ if (option.extendedSelectionRegion != extend) {
+ option.extendedSelectionRegion = extend;
+ m_view->setStyleOption(option);
+ }
+ }
+}
+
#include "kitemlistcontroller.moc"
MultiSelection
};
- KItemListController(QObject* parent = 0);
+ /**
+ * @param model Model of the controller. The ownership is passed to the controller.
+ * @param view View of the controller. The ownership is passed to the controller.
+ * @param parent Optional parent object.
+ */
+ KItemListController(KItemModelBase* model, KItemListView* view, QObject* parent = 0);
virtual ~KItemListController();
void setModel(KItemModelBase* model);
*/
qreal keyboardAnchorPos(int index) const;
+ /**
+ * Dependent on the selection-behavior the extendedSelectionRegion-property
+ * of the KItemListStyleOption from the view should be adjusted: If no
+ * rubberband selection is used the property should be enabled.
+ */
+ void updateExtendedSelectionRegion();
+
private:
bool m_singleClickActivation;
bool m_selectionTogglePressed;
font(),
fontMetrics(QFont()),
palette(),
- padding(0),
- horizontalMargin(0),
- verticalMargin(0),
- iconSize(KIconLoader::SizeMedium),
+ padding(-1),
+ horizontalMargin(-1),
+ verticalMargin(-1),
+ iconSize(-1),
extendedSelectionRegion(false),
maxTextSize()
{
#include "kitemlistview.h"
+#include <KDebug>
#include "kitemlistcontroller.h"
#include "kitemlistheader.h"
#include "kitemlistselectionmanager.h"
#include "private/kitemlistviewlayouter.h"
#include "private/kitemlistviewanimation.h"
-#include <KDebug>
-
#include <QCursor>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
KItemListView::~KItemListView()
{
- delete m_sizeHintResolver;
- m_sizeHintResolver = 0;
-}
-
-void KItemListView::setScrollOrientation(Qt::Orientation orientation)
-{
- const Qt::Orientation previousOrientation = m_layouter->scrollOrientation();
- if (orientation == previousOrientation) {
- return;
- }
-
- m_layouter->setScrollOrientation(orientation);
- m_animation->setScrollOrientation(orientation);
- m_sizeHintResolver->clearCache();
-
- if (m_grouped) {
- QMutableHashIterator<KItemListWidget*, KItemListGroupHeader*> it (m_visibleGroups);
- while (it.hasNext()) {
- it.next();
- it.value()->setScrollOrientation(orientation);
- }
- updateGroupHeaderHeight();
-
- }
-
- doLayout(NoAnimation);
-
- onScrollOrientationChanged(orientation, previousOrientation);
- emit scrollOrientationChanged(orientation, previousOrientation);
-}
-
-Qt::Orientation KItemListView::scrollOrientation() const
-{
- return m_layouter->scrollOrientation();
-}
+ // The group headers are children of the widgets created by
+ // widgetCreator(). So it is mandatory to delete the group headers
+ // first.
+ delete m_groupHeaderCreator;
+ m_groupHeaderCreator = 0;
-void KItemListView::setItemSize(const QSizeF& size)
-{
- const QSizeF previousSize = m_itemSize;
- if (size == previousSize) {
- return;
- }
+ delete m_widgetCreator;
+ m_widgetCreator = 0;
- // Skip animations when the number of rows or columns
- // are changed in the grid layout. Although the animation
- // engine can handle this usecase, it looks obtrusive.
- const bool animate = !changesItemGridLayout(m_layouter->size(),
- size,
- m_layouter->itemMargin());
-
- const bool alternateBackgroundsChanged = (m_visibleRoles.count() > 1) &&
- (( m_itemSize.isEmpty() && !size.isEmpty()) ||
- (!m_itemSize.isEmpty() && size.isEmpty()));
-
- m_itemSize = size;
-
- if (alternateBackgroundsChanged) {
- // For an empty item size alternate backgrounds are drawn if more than
- // one role is shown. Assure that the backgrounds for visible items are
- // updated when changing the size in this context.
- updateAlternateBackgrounds();
- }
-
- if (size.isEmpty()) {
- if (m_headerWidget->automaticColumnResizing()) {
- updatePreferredColumnWidths();
- } else {
- // Only apply the changed height and respect the header widths
- // set by the user
- const qreal currentWidth = m_layouter->itemSize().width();
- const QSizeF newSize(currentWidth, size.height());
- m_layouter->setItemSize(newSize);
- }
- } else {
- m_layouter->setItemSize(size);
- }
-
- m_sizeHintResolver->clearCache();
- doLayout(animate ? Animation : NoAnimation);
- onItemSizeChanged(size, previousSize);
-}
-
-QSizeF KItemListView::itemSize() const
-{
- return m_itemSize;
+ delete m_sizeHintResolver;
+ m_sizeHintResolver = 0;
}
void KItemListView::setScrollOffset(qreal offset)
void KItemListView::setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator)
{
+ if (m_widgetCreator) {
+ delete m_widgetCreator;
+ }
m_widgetCreator = widgetCreator;
}
KItemListWidgetCreatorBase* KItemListView::widgetCreator() const
{
+ if (!m_widgetCreator) {
+ m_widgetCreator = defaultWidgetCreator();
+ }
return m_widgetCreator;
}
void KItemListView::setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator)
{
+ if (m_groupHeaderCreator) {
+ delete m_groupHeaderCreator;
+ }
m_groupHeaderCreator = groupHeaderCreator;
}
KItemListGroupHeaderCreatorBase* KItemListView::groupHeaderCreator() const
{
+ if (!m_groupHeaderCreator) {
+ m_groupHeaderCreator = defaultGroupHeaderCreator();
+ }
return m_groupHeaderCreator;
}
-void KItemListView::setStyleOption(const KItemListStyleOption& option)
+QSizeF KItemListView::itemSize() const
{
- const KItemListStyleOption previousOption = m_styleOption;
- m_styleOption = option;
-
- bool animate = true;
- const QSizeF margin(option.horizontalMargin, option.verticalMargin);
- if (margin != m_layouter->itemMargin()) {
- // Skip animations when the number of rows or columns
- // are changed in the grid layout. Although the animation
- // engine can handle this usecase, it looks obtrusive.
- animate = !changesItemGridLayout(m_layouter->size(),
- m_layouter->itemSize(),
- margin);
- m_layouter->setItemMargin(margin);
- }
-
- if (m_grouped) {
- updateGroupHeaderHeight();
- }
-
- if (animate && previousOption.maxTextSize != option.maxTextSize) {
- // Animating a change of the maximum text size just results in expensive
- // temporary eliding and clipping operations and does not look good visually.
- animate = false;
- }
-
- QHashIterator<int, KItemListWidget*> it(m_visibleItems);
- while (it.hasNext()) {
- it.next();
- it.value()->setStyleOption(option);
- }
-
- m_sizeHintResolver->clearCache();
- m_layouter->markAsDirty();
- doLayout(animate ? Animation : NoAnimation);
-
- onStyleOptionChanged(option, previousOption);
+ return m_itemSize;
}
const KItemListStyleOption& KItemListView::styleOption() const
QSizeF KItemListView::itemSizeHint(int index) const
{
- return m_widgetCreator->itemSizeHint(index, this);
+ return widgetCreator()->itemSizeHint(index, this);
}
void KItemListView::setSupportsItemExpanding(bool supportsExpanding)
}
}
+void KItemListView::setItemSize(const QSizeF& size)
+{
+ const QSizeF previousSize = m_itemSize;
+ if (size == previousSize) {
+ return;
+ }
+
+ // Skip animations when the number of rows or columns
+ // are changed in the grid layout. Although the animation
+ // engine can handle this usecase, it looks obtrusive.
+ const bool animate = !changesItemGridLayout(m_layouter->size(),
+ size,
+ m_layouter->itemMargin());
+
+ const bool alternateBackgroundsChanged = (m_visibleRoles.count() > 1) &&
+ (( m_itemSize.isEmpty() && !size.isEmpty()) ||
+ (!m_itemSize.isEmpty() && size.isEmpty()));
+
+ m_itemSize = size;
+
+ if (alternateBackgroundsChanged) {
+ // For an empty item size alternate backgrounds are drawn if more than
+ // one role is shown. Assure that the backgrounds for visible items are
+ // updated when changing the size in this context.
+ updateAlternateBackgrounds();
+ }
+
+ if (size.isEmpty()) {
+ if (m_headerWidget->automaticColumnResizing()) {
+ updatePreferredColumnWidths();
+ } else {
+ // Only apply the changed height and respect the header widths
+ // set by the user
+ const qreal currentWidth = m_layouter->itemSize().width();
+ const QSizeF newSize(currentWidth, size.height());
+ m_layouter->setItemSize(newSize);
+ }
+ } else {
+ m_layouter->setItemSize(size);
+ }
+
+ m_sizeHintResolver->clearCache();
+ doLayout(animate ? Animation : NoAnimation);
+ onItemSizeChanged(size, previousSize);
+}
+
+void KItemListView::setStyleOption(const KItemListStyleOption& option)
+{
+ const KItemListStyleOption previousOption = m_styleOption;
+ m_styleOption = option;
+
+ bool animate = true;
+ const QSizeF margin(option.horizontalMargin, option.verticalMargin);
+ if (margin != m_layouter->itemMargin()) {
+ // Skip animations when the number of rows or columns
+ // are changed in the grid layout. Although the animation
+ // engine can handle this usecase, it looks obtrusive.
+ animate = !changesItemGridLayout(m_layouter->size(),
+ m_layouter->itemSize(),
+ margin);
+ m_layouter->setItemMargin(margin);
+ }
+
+ if (m_grouped) {
+ updateGroupHeaderHeight();
+ }
+
+ if (animate && previousOption.maxTextSize != option.maxTextSize) {
+ // Animating a change of the maximum text size just results in expensive
+ // temporary eliding and clipping operations and does not look good visually.
+ animate = false;
+ }
+
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+ it.value()->setStyleOption(option);
+ }
+
+ m_sizeHintResolver->clearCache();
+ m_layouter->markAsDirty();
+ doLayout(animate ? Animation : NoAnimation);
+
+ onStyleOptionChanged(option, previousOption);
+}
+
+void KItemListView::setScrollOrientation(Qt::Orientation orientation)
+{
+ const Qt::Orientation previousOrientation = m_layouter->scrollOrientation();
+ if (orientation == previousOrientation) {
+ return;
+ }
+
+ m_layouter->setScrollOrientation(orientation);
+ m_animation->setScrollOrientation(orientation);
+ m_sizeHintResolver->clearCache();
+
+ if (m_grouped) {
+ QMutableHashIterator<KItemListWidget*, KItemListGroupHeader*> it (m_visibleGroups);
+ while (it.hasNext()) {
+ it.next();
+ it.value()->setScrollOrientation(orientation);
+ }
+ updateGroupHeaderHeight();
+
+ }
+
+ doLayout(NoAnimation);
+
+ onScrollOrientationChanged(orientation, previousOrientation);
+ emit scrollOrientationChanged(orientation, previousOrientation);
+}
+
+Qt::Orientation KItemListView::scrollOrientation() const
+{
+ return m_layouter->scrollOrientation();
+}
+
+KItemListWidgetCreatorBase* KItemListView::defaultWidgetCreator() const
+{
+ return 0;
+}
+
+KItemListGroupHeaderCreatorBase* KItemListView::defaultGroupHeaderCreator() const
+{
+ return 0;
+}
+
void KItemListView::initializeItemListWidget(KItemListWidget* item)
{
Q_UNUSED(item);
void KItemListView::onModelChanged(KItemModelBase* current, KItemModelBase* previous)
{
- Q_UNUSED(current);
Q_UNUSED(previous);
+
+ m_sizeHintResolver->clearCache();
+ const int itemCount = current->count();
+ if (itemCount > 0) {
+ m_sizeHintResolver->itemsInserted(0, itemCount);
+ }
}
void KItemListView::onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous)
// by m_visibleWidgets and must be deleted manually after the animation has
// been finished.
recycleGroupHeaderForWidget(itemListWidget);
- m_widgetCreator->recycle(itemListWidget);
+ widgetCreator()->recycle(itemListWidget);
break;
}
KItemListWidget* KItemListView::createWidget(int index)
{
- KItemListWidget* widget = m_widgetCreator->create(this);
+ KItemListWidget* widget = widgetCreator()->create(this);
widget->setFlag(QGraphicsItem::ItemStacksBehindParent);
m_visibleItems.insert(index, widget);
m_visibleItems.remove(index);
m_visibleCells.remove(index);
- m_widgetCreator->recycle(widget);
+ widgetCreator()->recycle(widget);
}
void KItemListView::setWidgetIndex(KItemListWidget* widget, int index)
KItemListGroupHeader* groupHeader = m_visibleGroups.value(widget);
if (!groupHeader) {
- groupHeader = m_groupHeaderCreator->create(this);
+ groupHeader = groupHeaderCreator()->create(this);
groupHeader->setParentItem(widget);
m_visibleGroups.insert(widget, groupHeader);
connect(widget, SIGNAL(geometryChanged()), this, SLOT(slotGeometryOfGroupHeaderParentChanged()));
KItemListGroupHeader* header = m_visibleGroups.value(widget);
if (header) {
header->setParentItem(0);
- m_groupHeaderCreator->recycle(header);
+ groupHeaderCreator()->recycle(header);
m_visibleGroups.remove(widget);
disconnect(widget, SIGNAL(geometryChanged()), this, SLOT(slotGeometryOfGroupHeaderParentChanged()));
}
// Calculate the preferred column withs for each item and ignore values
// smaller than the width for showing the headline unclipped.
+ const KItemListWidgetCreatorBase* creator = widgetCreator();
int calculatedItemCount = 0;
bool maxTimeExceeded = false;
foreach (const KItemRange& itemRange, itemRanges) {
for (int i = startIndex; i <= endIndex; ++i) {
foreach (const QByteArray& visibleRole, visibleRoles()) {
qreal maxWidth = widths.value(visibleRole, 0);
- const qreal width = m_widgetCreator->preferredRoleColumnWidth(visibleRole, i, this);
+ const qreal width = creator->preferredRoleColumnWidth(visibleRole, i, this);
maxWidth = qMax(width, maxWidth);
widths.insert(visibleRole, maxWidth);
}
{
Q_ASSERT(m_itemSize.isEmpty());
Q_ASSERT(m_headerWidget->automaticColumnResizing());
+ if (m_visibleRoles.isEmpty()) {
+ return;
+ }
// Calculate the maximum size of an item by considering the
// visible role sizes and apply them to the layouter. If the
class KItemListViewAnimation;
class KItemListViewLayouter;
class KItemListWidget;
+class KItemListWidgetInformant;
class KItemListWidgetCreatorBase;
class KItemListViewCreatorBase;
class QTimer;
* a GraphicsItem. Each visible item is represented by a KItemListWidget.
*
* The created view must be applied to the KItemListController with
- * KItemListController::setView(). For showing a custom model it is not
- * mandatory to derive from KItemListView, all that is necessary is
- * to set a widget-creator that is capable to create KItemListWidgets
- * showing the model items. A widget-creator can be set with
- * KItemListView::setWidgetCreator().
+ * KItemListController::setView() or with the constructor of
+ * KItemListController.
*
* @see KItemListWidget
* @see KItemModelBase
KItemListView(QGraphicsWidget* parent = 0);
virtual ~KItemListView();
- /**
- * If the scroll-orientation is vertical, the items are ordered
- * from top to bottom (= default setting). If the scroll-orientation
- * is horizontal, the items are ordered from left to right.
- */
- void setScrollOrientation(Qt::Orientation orientation);
- Qt::Orientation scrollOrientation() const;
-
- void setItemSize(const QSizeF& size);
- QSizeF itemSize() const;
-
/**
* Offset of the scrollbar that represents the scroll-orientation
* (see setScrollOrientation()).
* <code>
* itemListView->setWidgetCreator(new KItemListWidgetCreator<X>());
* </code>
- * Note that the ownership of the widget creator is not transferred to
- * the item-list view: One instance of a widget creator might get shared
- * by several item-list view instances.
+ * The ownership of the widget creator is transferred to
+ * the item-list view.
**/
void setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator);
KItemListWidgetCreatorBase* widgetCreator() const;
+ /**
+ * Sets the creator that creates a group header. Usually it is sufficient
+ * to implement a custom header widget X derived from KItemListGroupHeader and
+ * set the creator by:
+ * <code>
+ * itemListView->setGroupHeaderCreator(new KItemListGroupHeaderCreator<X>());
+ * </code>
+ * The ownership of the gropup header creator is transferred to
+ * the item-list view.
+ **/
void setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator);
KItemListGroupHeaderCreatorBase* groupHeaderCreator() const;
- void setStyleOption(const KItemListStyleOption& option);
+ QSizeF itemSize() const;
+
const KItemListStyleOption& styleOption() const;
/** @reimp */
void roleEditingFinished(int index, const QByteArray& role, const QVariant& value);
protected:
+ void setItemSize(const QSizeF& size);
+ void setStyleOption(const KItemListStyleOption& option);
+
+ /**
+ * If the scroll-orientation is vertical, the items are ordered
+ * from top to bottom (= default setting). If the scroll-orientation
+ * is horizontal, the items are ordered from left to right.
+ */
+ void setScrollOrientation(Qt::Orientation orientation);
+ Qt::Orientation scrollOrientation() const;
+
+ /**
+ * Factory method for creating a default widget-creator. The method will be used
+ * in case if setWidgetCreator() has not been set by the application.
+ * @return New instance of the widget-creator that should be used per
+ * default.
+ */
+ virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const;
+
+ /**
+ * Factory method for creating a default group-header-creator. The method will be used
+ * in case if setGroupHeaderCreator() has not been set by the application.
+ * @return New instance of the group-header-creator that should be used per
+ * default.
+ */
+ virtual KItemListGroupHeaderCreatorBase* defaultGroupHeaderCreator() const;
+
/**
* Is called when creating a new KItemListWidget instance and allows derived
* classes to do a custom initialization.
KItemListController* m_controller;
KItemModelBase* m_model;
QList<QByteArray> m_visibleRoles;
- KItemListWidgetCreatorBase* m_widgetCreator;
- KItemListGroupHeaderCreatorBase* m_groupHeaderCreator;
+ mutable KItemListWidgetCreatorBase* m_widgetCreator;
+ mutable KItemListGroupHeaderCreatorBase* m_groupHeaderCreator;
KItemListStyleOption m_styleOption;
QHash<int, KItemListWidget*> m_visibleItems;
/**
* @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:
+ KItemListWidgetCreator();
virtual ~KItemListWidgetCreator();
virtual KItemListWidget* create(KItemListView* view);
virtual qreal preferredRoleColumnWidth(const QByteArray& role,
int index,
const KItemListView* view) const;
+private:
+ KItemListWidgetInformant* m_informant;
};
+template <class T>
+KItemListWidgetCreator<T>::KItemListWidgetCreator() :
+ m_informant(T::createInformant())
+{
+}
+
template <class T>
KItemListWidgetCreator<T>::~KItemListWidgetCreator()
{
+ delete m_informant;
}
template <class T>
{
KItemListWidget* widget = static_cast<KItemListWidget*>(popRecycleableWidget());
if (!widget) {
- widget = new T(view);
+ widget = new T(m_informant, view);
addCreatedWidget(widget);
}
return widget;
template<class T>
QSizeF KItemListWidgetCreator<T>::itemSizeHint(int index, const KItemListView* view) const
{
- return T::itemSizeHint(index, view);
+ return m_informant->itemSizeHint(index, view);
}
template<class T>
int index,
const KItemListView* view) const
{
- return T::preferredRoleColumnWidth(role, index, view);
+ return m_informant->preferredRoleColumnWidth(role, index, view);
}
/**
#include <QPropertyAnimation>
#include <QStyleOption>
-KItemListWidget::KItemListWidget(QGraphicsItem* parent) :
+KItemListWidgetInformant::KItemListWidgetInformant()
+{
+}
+
+KItemListWidgetInformant::~KItemListWidgetInformant()
+{
+}
+
+KItemListWidget::KItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) :
QGraphicsWidget(parent, 0),
+ m_informant(informant),
m_index(-1),
m_selected(false),
m_current(false),
#include <QStyle>
class KItemListSelectionToggle;
+class KItemListView;
class QPropertyAnimation;
+/**
+ * @brief Provides information for creating an instance of KItemListWidget.
+ *
+ * KItemListView only creates KItemListWidget instances for the visible
+ * area. For calculating the required size of all items the expected
+ * size for the invisible items must be accessible. KItemListWidgetInformant
+ * provides this information.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetInformant
+{
+public:
+ KItemListWidgetInformant();
+ virtual ~KItemListWidgetInformant();
+
+ virtual QSizeF itemSizeHint(int index, const KItemListView* view) const = 0;
+
+ virtual qreal preferredRoleColumnWidth(const QByteArray& role,
+ int index,
+ const KItemListView* view) const = 0;
+};
+
/**
* @brief Widget that shows a visible item from the model.
*
Q_OBJECT
public:
- KItemListWidget(QGraphicsItem* parent);
+ KItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent);
virtual ~KItemListWidget();
void setIndex(int index);
*/
qreal hoverOpacity() const;
+ const KItemListWidgetInformant* informant() const;
+
private slots:
void slotHoverAnimationFinished();
private:
Q_PROPERTY(qreal hoverOpacity READ hoverOpacity WRITE setHoverOpacity)
+ KItemListWidgetInformant* m_informant;
int m_index;
bool m_selected;
bool m_current;
QByteArray m_editedRole;
};
+
+inline const KItemListWidgetInformant* KItemListWidget::informant() const
+{
+ return m_informant;
+}
+
#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "kstandarditem.h"
+
+KStandardItem::KStandardItem(KStandardItem* parent) :
+ m_text(),
+ m_icon(),
+ m_group(),
+ m_parent(parent),
+ m_children(),
+ m_model(0)
+{
+}
+
+KStandardItem::KStandardItem(const QString& text, KStandardItem* parent) :
+ m_text(text),
+ m_icon(),
+ m_group(),
+ m_parent(parent),
+ m_children(),
+ m_model(0)
+{
+}
+
+KStandardItem::KStandardItem(const QIcon& icon, const QString& text, KStandardItem* parent) :
+ m_text(text),
+ m_icon(icon),
+ m_group(),
+ m_parent(parent),
+ m_children(),
+ m_model(0)
+{
+}
+
+KStandardItem::~KStandardItem()
+{
+}
+
+void KStandardItem::setText(const QString& text)
+{
+ m_text = text;
+}
+
+QString KStandardItem::text() const
+{
+ return m_text;
+}
+
+void KStandardItem::setIcon(const QIcon& icon)
+{
+ m_icon = icon;
+}
+
+QIcon KStandardItem::icon() const
+{
+ return m_icon;
+}
+
+void KStandardItem::setGroup(const QString& group)
+{
+ m_group = group;
+}
+
+QString KStandardItem::group() const
+{
+ return m_group;
+}
+
+void KStandardItem::setParent(KStandardItem* parent)
+{
+ // TODO: not implemented yet
+ m_parent = parent;
+}
+
+KStandardItem* KStandardItem::parent() const
+{
+ return m_parent;
+}
+
+QList<KStandardItem*> KStandardItem::children() const
+{
+ return m_children;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#ifndef KSTANDARDITEM_H
+#define KSTANDARDITEM_H
+
+#include <libdolphin_export.h>
+
+#include <QIcon>
+#include <QList>
+
+class KStandardItemModel;
+
+/**
+ * @brief Represents and item of KStandardItemModel.
+ *
+ * Provides setter- and getter-methods for most commonly
+ * used properties.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KStandardItem
+{
+
+public:
+ explicit KStandardItem(KStandardItem* parent = 0);
+ explicit KStandardItem(const QString& text, KStandardItem* parent = 0);
+ KStandardItem(const QIcon& icon, const QString& text, KStandardItem* parent = 0);
+ virtual ~KStandardItem();
+
+ void setText(const QString& text);
+ QString text() const;
+
+ void setIcon(const QIcon& icon);
+ QIcon icon() const;
+
+ void setGroup(const QString& group);
+ QString group() const;
+
+ void setParent(KStandardItem* parent);
+ KStandardItem* parent() const;
+
+ QList<KStandardItem*> children() const;
+
+private:
+ QString m_text;
+ QIcon m_icon;
+ QString m_group;
+ KStandardItem* m_parent;
+ QList<KStandardItem*> m_children;
+ KStandardItemModel* m_model;
+
+ friend class KStandardItemModel;
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "kstandarditemlistview.h"
+
+#include <KDebug>
+#include <KIconLoader>
+#include "kstandarditemlistwidget.h"
+
+KStandardItemListView::KStandardItemListView(QGraphicsWidget* parent) :
+ KItemListView(parent),
+ m_itemLayout(DetailsLayout)
+{
+ setAcceptDrops(true);
+ setScrollOrientation(Qt::Vertical);
+ setVisibleRoles(QList<QByteArray>() << "text");
+}
+
+KStandardItemListView::~KStandardItemListView()
+{
+}
+
+void KStandardItemListView::setItemLayout(ItemLayout layout)
+{
+ if (m_itemLayout == layout) {
+ return;
+ }
+
+ beginTransaction();
+
+ const ItemLayout previous = m_itemLayout;
+ m_itemLayout = layout;
+
+ switch (layout) {
+ case IconsLayout:
+ setScrollOrientation(Qt::Vertical);
+ setSupportsItemExpanding(false);
+ break;
+ case DetailsLayout:
+ setScrollOrientation(Qt::Vertical);
+ setSupportsItemExpanding(true);
+ break;
+ case CompactLayout:
+ setScrollOrientation(Qt::Horizontal);
+ setSupportsItemExpanding(false);
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ onItemLayoutChanged(layout, previous);
+
+ endTransaction();
+}
+
+KStandardItemListView::ItemLayout KStandardItemListView::itemLayout() const
+{
+ return m_itemLayout;
+}
+
+KItemListWidgetCreatorBase* KStandardItemListView::defaultWidgetCreator() const
+{
+ return new KItemListWidgetCreator<KStandardItemListWidget>();
+}
+
+KItemListGroupHeaderCreatorBase* KStandardItemListView::defaultGroupHeaderCreator() const
+{
+ return 0; // TODO: new KItemListGroupHeaderCreator<KStandardItemListGroupHeader>()
+}
+
+void KStandardItemListView::initializeItemListWidget(KItemListWidget* item)
+{
+ KStandardItemListWidget* standardItemListWidget = qobject_cast<KStandardItemListWidget*>(item);
+ Q_ASSERT(standardItemListWidget);
+
+ switch (itemLayout()) {
+ case IconsLayout: standardItemListWidget->setLayout(KStandardItemListWidget::IconsLayout); break;
+ case CompactLayout: standardItemListWidget->setLayout(KStandardItemListWidget::CompactLayout); break;
+ case DetailsLayout: standardItemListWidget->setLayout(KStandardItemListWidget::DetailsLayout); break;
+ default: Q_ASSERT(false); break;
+ }
+
+ standardItemListWidget->setSupportsItemExpanding(supportsItemExpanding());
+}
+
+
+bool KStandardItemListView::itemSizeHintUpdateRequired(const QSet<QByteArray>& changedRoles) const
+{
+ // Even if the icons have a different size they are always aligned within
+ // the area defined by KItemStyleOption.iconSize and hence result in no
+ // change of the item-size.
+ const bool containsIconName = changedRoles.contains("iconName");
+ const bool containsIconPixmap = changedRoles.contains("iconPixmap");
+ const int count = changedRoles.count();
+
+ const bool iconChanged = (containsIconName && containsIconPixmap && count == 2) ||
+ (containsIconName && count == 1) ||
+ (containsIconPixmap && count == 1);
+ return !iconChanged;
+}
+
+void KStandardItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ updateLayoutOfVisibleItems();
+}
+
+void KStandardItemListView::onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ updateLayoutOfVisibleItems();
+}
+
+void KStandardItemListView::onSupportsItemExpandingChanged(bool supportsExpanding)
+{
+ Q_UNUSED(supportsExpanding);
+ updateLayoutOfVisibleItems();
+}
+
+
+void KStandardItemListView::polishEvent()
+{
+ switch (m_itemLayout) {
+ case IconsLayout: applyDefaultStyleOption(KIconLoader::SizeMedium, 2, 4, 8); break;
+ case CompactLayout: applyDefaultStyleOption(KIconLoader::SizeSmall, 2, 8, 0); break;
+ case DetailsLayout: applyDefaultStyleOption(KIconLoader::SizeSmall, 2, 0, 0); break;
+ default: Q_ASSERT(false); break;
+ }
+
+ QGraphicsWidget::polishEvent();
+}
+
+void KStandardItemListView::applyDefaultStyleOption(int iconSize,
+ int padding,
+ int horizontalMargin,
+ int verticalMargin)
+{
+ KItemListStyleOption option = styleOption();
+
+ bool changed = false;
+ if (option.iconSize < 0) {
+ option.iconSize = iconSize;
+ changed = true;
+ }
+ if (option.padding < 0) {
+ option.padding = padding;
+ changed = true;
+ }
+ if (option.horizontalMargin < 0) {
+ option.horizontalMargin = horizontalMargin;
+ changed = true;
+ }
+ if (option.verticalMargin < 0) {
+ option.verticalMargin = verticalMargin;
+ changed = true;
+ }
+
+ if (changed) {
+ setStyleOption(option);
+ }
+}
+
+void KStandardItemListView::updateLayoutOfVisibleItems()
+{
+ if (model()) {
+ foreach (KItemListWidget* widget, visibleItemListWidgets()) {
+ initializeItemListWidget(widget);
+ }
+ }
+}
+
+#include "kstandarditemlistview.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#ifndef KSTANDARDITEMLISTVIEW_H
+#define KSTANDARDITEMLISTVIEW_H
+
+#include <libdolphin_export.h>
+
+#include <kitemviews/kitemlistview.h>
+
+/**
+ * @brief Provides layouts for icons-, compact- and details-view.
+ *
+ * Together with the KStandardItemModel lists for standard usecases
+ * can be created in a straight forward way.
+ *
+ * Example code:
+ * <code>
+ * KStandardItemListView* view = new KStandardItemListView();
+ * KStandardItemModel* model = new KStandardItemModel();
+ * model->appendItem(new KStandardItem("Item 1"));
+ * model->appendItem(new KStandardItem("Item 2"));
+ * KItemListController* controller = new KItemListController(model, view);
+ * KItemListContainer* container = new KItemListContainer(controller, parentWidget);
+ * </code>
+ */
+class LIBDOLPHINPRIVATE_EXPORT KStandardItemListView : public KItemListView
+{
+ Q_OBJECT
+
+public:
+ enum ItemLayout
+ {
+ IconsLayout,
+ CompactLayout,
+ DetailsLayout
+ };
+
+ KStandardItemListView(QGraphicsWidget* parent = 0);
+ virtual ~KStandardItemListView();
+
+ void setItemLayout(ItemLayout layout);
+ ItemLayout itemLayout() const;
+
+protected:
+ virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const;
+ virtual KItemListGroupHeaderCreatorBase* defaultGroupHeaderCreator() const;
+ virtual void initializeItemListWidget(KItemListWidget* item);
+ virtual bool itemSizeHintUpdateRequired(const QSet<QByteArray>& changedRoles) const;
+ virtual void onItemLayoutChanged(ItemLayout current, ItemLayout previous);
+ virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
+ virtual void onSupportsItemExpandingChanged(bool supportsExpanding);
+ virtual void polishEvent();
+
+private:
+ void applyDefaultStyleOption(int iconSize, int padding, int horizontalMargin, int verticalMargin);
+ void updateLayoutOfVisibleItems();
+
+private:
+ ItemLayout m_itemLayout;
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "kstandarditemlistwidget.h"
+
+#include "kfileitemlistview.h"
+#include "kfileitemmodel.h"
+
+#include <KIcon>
+#include <KIconEffect>
+#include <KIconLoader>
+#include <KLocale>
+#include <kratingpainter.h>
+#include <KStringHandler>
+#include <KDebug>
+
+#include "private/kfileitemclipboard.h"
+#include "private/kitemlistroleeditor.h"
+#include "private/kpixmapmodifier.h"
+
+#include <QFontMetricsF>
+#include <QGraphicsScene>
+#include <QGraphicsSceneResizeEvent>
+#include <QGraphicsView>
+#include <QPainter>
+#include <QStyleOption>
+#include <QTextLayout>
+#include <QTextLine>
+
+// #define KFILEITEMLISTWIDGET_DEBUG
+
+KStandardItemListWidgetInformant::KStandardItemListWidgetInformant() :
+ KItemListWidgetInformant()
+{
+}
+
+KStandardItemListWidgetInformant::~KStandardItemListWidgetInformant()
+{
+}
+
+QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemListView* view) const
+{
+ const QHash<QByteArray, QVariant> values = view->model()->data(index);
+ const KItemListStyleOption& option = view->styleOption();
+ const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
+
+ switch (static_cast<const KStandardItemListView*>(view)->itemLayout()) {
+ case KStandardItemListWidget::IconsLayout: {
+ const QString text = KStringHandler::preProcessWrap(values["text"].toString());
+
+ const qreal itemWidth = view->itemSize().width();
+ const qreal maxWidth = itemWidth - 2 * option.padding;
+ QTextLine line;
+
+ // Calculate the number of lines required for wrapping the name
+ QTextOption textOption(Qt::AlignHCenter);
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+
+ qreal textHeight = 0;
+ QTextLayout layout(text, option.font);
+ layout.setTextOption(textOption);
+ layout.beginLayout();
+ while ((line = layout.createLine()).isValid()) {
+ line.setLineWidth(maxWidth);
+ line.naturalTextWidth();
+ textHeight += line.height();
+ }
+ layout.endLayout();
+
+ // Add one line for each additional information
+ textHeight += additionalRolesCount * option.fontMetrics.lineSpacing();
+
+ const qreal maxTextHeight = option.maxTextSize.height();
+ if (maxTextHeight > 0 && textHeight > maxTextHeight) {
+ textHeight = maxTextHeight;
+ }
+
+ return QSizeF(itemWidth, textHeight + option.iconSize + option.padding * 3);
+ }
+
+ case KStandardItemListWidget::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 = roleText(role, values);
+ const qreal requiredWidth = option.fontMetrics.width(text);
+ maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth);
+ }
+
+ qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth;
+ const qreal maxWidth = option.maxTextSize.width();
+ if (maxWidth > 0 && width > maxWidth) {
+ width = maxWidth;
+ }
+ const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing());
+ return QSizeF(width, height);
+ }
+
+ case KStandardItemListWidget::DetailsLayout: {
+ const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height());
+ return QSizeF(-1, height);
+ }
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ return QSize();
+}
+
+qreal KStandardItemListWidgetInformant::preferredRoleColumnWidth(const QByteArray& role,
+ int index,
+ const KItemListView* view) const
+{
+ const QHash<QByteArray, QVariant> values = view->model()->data(index);
+ const KItemListStyleOption& option = view->styleOption();
+
+ const QString text = roleText(role, values);
+ qreal width = KStandardItemListWidget::columnPadding(option);
+
+ if (role == "rating") {
+ width += KStandardItemListWidget::preferredRatingSize(option).width();
+ } else {
+ width += option.fontMetrics.width(text);
+
+ if (role == "text") {
+ // 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;
+}
+
+QString KStandardItemListWidgetInformant::roleText(const QByteArray& role,
+ const QHash<QByteArray, QVariant>& values) const
+{
+ if (role == "rating") {
+ // Always use an empty text, as the rating is shown by the image m_rating.
+ return QString();
+ }
+ return values.value(role).toString();
+}
+
+KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) :
+ KItemListWidget(informant, parent),
+ m_isCut(false),
+ m_isHidden(false),
+ m_isExpandable(false),
+ m_supportsItemExpanding(false),
+ m_dirtyLayout(true),
+ m_dirtyContent(true),
+ m_dirtyContentRoles(),
+ m_layout(IconsLayout),
+ m_pixmapPos(),
+ m_pixmap(),
+ m_scaledPixmapSize(),
+ m_iconRect(),
+ m_hoverPixmap(),
+ m_textInfo(),
+ m_textRect(),
+ m_sortedVisibleRoles(),
+ m_expansionArea(),
+ m_customTextColor(),
+ m_additionalInfoTextColor(),
+ m_overlay(),
+ m_rating(),
+ m_roleEditor(0)
+{
+}
+
+KStandardItemListWidget::~KStandardItemListWidget()
+{
+ qDeleteAll(m_textInfo);
+ m_textInfo.clear();
+
+ delete m_roleEditor;
+}
+
+void KStandardItemListWidget::setLayout(Layout layout)
+{
+ if (m_layout != layout) {
+ m_layout = layout;
+ m_dirtyLayout = true;
+ updateAdditionalInfoTextColor();
+ update();
+ }
+}
+
+KStandardItemListWidget::Layout KStandardItemListWidget::layout() const
+{
+ return m_layout;
+}
+
+void KStandardItemListWidget::setSupportsItemExpanding(bool supportsItemExpanding)
+{
+ if (m_supportsItemExpanding != supportsItemExpanding) {
+ m_supportsItemExpanding = supportsItemExpanding;
+ m_dirtyLayout = true;
+ update();
+ }
+}
+
+bool KStandardItemListWidget::supportsItemExpanding() const
+{
+ return m_supportsItemExpanding;
+}
+
+void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+ const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
+
+ KItemListWidget::paint(painter, option, widget);
+
+ if (!m_expansionArea.isEmpty()) {
+ drawSiblingsInformation(painter);
+ }
+
+ const KItemListStyleOption& itemListStyleOption = styleOption();
+ if (isHovered()) {
+ // Blend the unhovered and hovered pixmap if the hovering
+ // animation is ongoing
+ if (hoverOpacity() < 1.0) {
+ drawPixmap(painter, m_pixmap);
+ }
+
+ const qreal opacity = painter->opacity();
+ painter->setOpacity(hoverOpacity() * opacity);
+ drawPixmap(painter, m_hoverPixmap);
+ painter->setOpacity(opacity);
+ } else {
+ drawPixmap(painter, m_pixmap);
+ }
+
+ painter->setFont(itemListStyleOption.font);
+ painter->setPen(textColor());
+ const TextInfo* textInfo = m_textInfo.value("text");
+ painter->drawStaticText(textInfo->pos, textInfo->staticText);
+
+ bool clipAdditionalInfoBounds = false;
+ if (m_supportsItemExpanding) {
+ // Prevent a possible overlapping of the additional-information texts
+ // with the icon. This can happen if the user has minimized the width
+ // of the name-column to a very small value.
+ const qreal minX = m_pixmapPos.x() + m_pixmap.width() + 4 * itemListStyleOption.padding;
+ if (textInfo->pos.x() + columnWidth("text") > minX) {
+ clipAdditionalInfoBounds = true;
+ painter->save();
+ painter->setClipRect(minX, 0, size().width() - minX, size().height(), Qt::IntersectClip);
+ }
+ }
+
+ painter->setPen(m_additionalInfoTextColor);
+ painter->setFont(itemListStyleOption.font);
+
+ for (int i = 1; i < m_sortedVisibleRoles.count(); ++i) {
+ const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles[i]);
+ painter->drawStaticText(textInfo->pos, textInfo->staticText);
+ }
+
+ if (!m_rating.isNull()) {
+ const TextInfo* ratingTextInfo = m_textInfo.value("rating");
+ QPointF pos = ratingTextInfo->pos;
+ const Qt::Alignment align = ratingTextInfo->staticText.textOption().alignment();
+ if (align & Qt::AlignHCenter) {
+ pos.rx() += (size().width() - m_rating.width()) / 2;
+ }
+ painter->drawPixmap(pos, m_rating);
+ }
+
+ if (clipAdditionalInfoBounds) {
+ painter->restore();
+ }
+
+#ifdef KFILEITEMLISTWIDGET_DEBUG
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(Qt::green);
+ painter->drawRect(m_iconRect);
+
+ painter->setPen(Qt::red);
+ painter->drawText(QPointF(0, itemListStyleOption.fontMetrics.height()), QString::number(index()));
+ painter->drawRect(rect());
+#endif
+}
+
+QRectF KStandardItemListWidget::iconRect() const
+{
+ const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
+ return m_iconRect;
+}
+
+QRectF KStandardItemListWidget::textRect() const
+{
+ const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
+ return m_textRect;
+}
+
+QRectF KStandardItemListWidget::textFocusRect() const
+{
+ // In the compact- and details-layout a larger textRect() is returned to be aligned
+ // with the iconRect(). This is useful to have a larger selection/hover-area
+ // when having a quite large icon size but only one line of text. Still the
+ // focus rectangle should be shown as narrow as possible around the text.
+
+ const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
+
+ switch (m_layout) {
+ case CompactLayout: {
+ QRectF rect = m_textRect;
+ const TextInfo* topText = m_textInfo.value(m_sortedVisibleRoles.first());
+ const TextInfo* bottomText = m_textInfo.value(m_sortedVisibleRoles.last());
+ rect.setTop(topText->pos.y());
+ rect.setBottom(bottomText->pos.y() + bottomText->staticText.size().height());
+ return rect;
+ }
+
+ case DetailsLayout: {
+ QRectF rect = m_textRect;
+ const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles.first());
+ rect.setTop(textInfo->pos.y());
+ rect.setBottom(textInfo->pos.y() + textInfo->staticText.size().height());
+ return rect;
+ }
+
+ default:
+ break;
+ }
+
+ return m_textRect;
+}
+
+QRectF KStandardItemListWidget::expansionToggleRect() const
+{
+ const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
+ return m_isExpandable ? m_expansionArea : QRectF();
+}
+
+QRectF KStandardItemListWidget::selectionToggleRect() const
+{
+ const_cast<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
+
+ const int iconHeight = styleOption().iconSize;
+
+ int toggleSize = KIconLoader::SizeSmall;
+ if (iconHeight >= KIconLoader::SizeEnormous) {
+ toggleSize = KIconLoader::SizeMedium;
+ } else if (iconHeight >= KIconLoader::SizeLarge) {
+ toggleSize = KIconLoader::SizeSmallMedium;
+ }
+
+ QPointF pos = iconRect().topLeft();
+
+ // If the selection toggle has a very small distance to the
+ // widget borders, the size of the selection toggle will get
+ // increased to prevent an accidental clicking of the item
+ // when trying to hit the toggle.
+ const int widgetHeight = size().height();
+ const int widgetWidth = size().width();
+ const int minMargin = 2;
+
+ if (toggleSize + minMargin * 2 >= widgetHeight) {
+ pos.rx() -= (widgetHeight - toggleSize) / 2;
+ toggleSize = widgetHeight;
+ pos.setY(0);
+ }
+ if (toggleSize + minMargin * 2 >= widgetWidth) {
+ pos.ry() -= (widgetWidth - toggleSize) / 2;
+ toggleSize = widgetWidth;
+ pos.setX(0);
+ }
+
+ return QRectF(pos, QSizeF(toggleSize, toggleSize));
+}
+
+KItemListWidgetInformant* KStandardItemListWidget::createInformant()
+{
+ return new KStandardItemListWidgetInformant();
+}
+
+void KStandardItemListWidget::invalidateCache()
+{
+ m_dirtyLayout = true;
+ m_dirtyContent = true;
+}
+
+void KStandardItemListWidget::refreshCache()
+{
+}
+
+bool KStandardItemListWidget::isRoleRightAligned(const QByteArray& role) const
+{
+ Q_UNUSED(role);
+ return false;
+}
+
+void KStandardItemListWidget::setTextColor(const QColor& color)
+{
+ if (color != m_customTextColor) {
+ m_customTextColor = color;
+ updateAdditionalInfoTextColor();
+ update();
+ }
+}
+
+QColor KStandardItemListWidget::textColor() const
+{
+ if (m_customTextColor.isValid() && !isSelected()) {
+ return m_customTextColor;
+ }
+
+ const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive;
+ const QPalette::ColorRole role = isSelected() ? QPalette::HighlightedText : QPalette::Text;
+ return styleOption().palette.brush(group, role).color();
+}
+
+void KStandardItemListWidget::setOverlay(const QPixmap& overlay)
+{
+ m_overlay = overlay;
+ m_dirtyContent = true;
+ update();
+}
+
+QPixmap KStandardItemListWidget::overlay() const
+{
+ return m_overlay;
+}
+
+
+QString KStandardItemListWidget::roleText(const QByteArray& role,
+ const QHash<QByteArray, QVariant>& values) const
+{
+ return static_cast<const KStandardItemListWidgetInformant*>(informant())->roleText(role, values);
+}
+
+void KStandardItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
+ const QSet<QByteArray>& roles)
+{
+ Q_UNUSED(current);
+
+ m_dirtyContent = true;
+
+ QSet<QByteArray> dirtyRoles;
+ if (roles.isEmpty()) {
+ dirtyRoles = visibleRoles().toSet();
+ dirtyRoles.insert("iconPixmap");
+ dirtyRoles.insert("iconName");
+ } else {
+ dirtyRoles = roles;
+ }
+
+ QSetIterator<QByteArray> it(dirtyRoles);
+ while (it.hasNext()) {
+ const QByteArray& role = it.next();
+ m_dirtyContentRoles.insert(role);
+ }
+}
+
+void KStandardItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
+ const QList<QByteArray>& previous)
+{
+ Q_UNUSED(previous);
+ m_sortedVisibleRoles = current;
+ m_dirtyLayout = true;
+}
+
+void KStandardItemListWidget::columnWidthChanged(const QByteArray& role,
+ qreal current,
+ qreal previous)
+{
+ Q_UNUSED(role);
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ m_dirtyLayout = true;
+}
+
+void KStandardItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
+ const KItemListStyleOption& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ updateAdditionalInfoTextColor();
+ m_dirtyLayout = true;
+}
+
+void KStandardItemListWidget::hoveredChanged(bool hovered)
+{
+ Q_UNUSED(hovered);
+ m_dirtyLayout = true;
+}
+
+void KStandardItemListWidget::selectedChanged(bool selected)
+{
+ Q_UNUSED(selected);
+ updateAdditionalInfoTextColor();
+}
+
+void KStandardItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ m_dirtyLayout = true;
+}
+
+void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const QByteArray& previous)
+{
+ Q_UNUSED(previous);
+
+ QGraphicsView* parent = scene()->views()[0];
+ if (current.isEmpty() || !parent || current != "text") {
+ if (m_roleEditor) {
+ emit roleEditingCanceled(index(), current, data().value(current));
+ m_roleEditor->deleteLater();
+ m_roleEditor = 0;
+ }
+ return;
+ }
+
+ Q_ASSERT(!m_roleEditor);
+
+ const TextInfo* textInfo = m_textInfo.value("text");
+
+ m_roleEditor = new KItemListRoleEditor(parent);
+ m_roleEditor->setIndex(index());
+ m_roleEditor->setRole(current);
+
+ const QString text = data().value(current).toString();
+ m_roleEditor->setPlainText(text);
+
+ QTextOption textOption = textInfo->staticText.textOption();
+ m_roleEditor->document()->setDefaultTextOption(textOption);
+
+ // Select the text without MIME-type extension
+ int selectionLength = text.length();
+
+ const QString extension = KMimeType::extractKnownExtension(text);
+ if (!extension.isEmpty()) {
+ selectionLength -= extension.length() + 1;
+ }
+
+ if (selectionLength > 0) {
+ QTextCursor cursor = m_roleEditor->textCursor();
+ cursor.movePosition(QTextCursor::StartOfBlock);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selectionLength);
+ m_roleEditor->setTextCursor(cursor);
+ }
+
+ connect(m_roleEditor, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
+ connect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+
+ // Adjust the geometry of the editor
+ QRectF rect = roleEditingRect(current);
+ const int frameWidth = m_roleEditor->frameWidth();
+ rect.adjust(-frameWidth, -frameWidth, frameWidth, frameWidth);
+ rect.translate(pos());
+ if (rect.right() > parent->width()) {
+ rect.setWidth(parent->width() - rect.left());
+ }
+ m_roleEditor->setGeometry(rect.toRect());
+ m_roleEditor->show();
+ m_roleEditor->setFocus();
+}
+
+void KStandardItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
+{
+ if (m_roleEditor) {
+ setEditedRole(QByteArray());
+ Q_ASSERT(!m_roleEditor);
+ }
+
+ KItemListWidget::resizeEvent(event);
+
+ m_dirtyLayout = true;
+}
+
+void KStandardItemListWidget::showEvent(QShowEvent* event)
+{
+ KItemListWidget::showEvent(event);
+
+ // Listen to changes of the clipboard to mark the item as cut/uncut
+ KFileItemClipboard* clipboard = KFileItemClipboard::instance();
+
+ const KUrl itemUrl = data().value("url").value<KUrl>();
+ m_isCut = clipboard->isCut(itemUrl);
+
+ connect(clipboard, SIGNAL(cutItemsChanged()),
+ this, SLOT(slotCutItemsChanged()));
+}
+
+void KStandardItemListWidget::hideEvent(QHideEvent* event)
+{
+ disconnect(KFileItemClipboard::instance(), SIGNAL(cutItemsChanged()),
+ this, SLOT(slotCutItemsChanged()));
+
+ KItemListWidget::hideEvent(event);
+}
+
+void KStandardItemListWidget::slotCutItemsChanged()
+{
+ const KUrl itemUrl = data().value("url").value<KUrl>();
+ const bool isCut = KFileItemClipboard::instance()->isCut(itemUrl);
+ if (m_isCut != isCut) {
+ m_isCut = isCut;
+ m_pixmap = QPixmap();
+ m_dirtyContent = true;
+ update();
+ }
+}
+
+void KStandardItemListWidget::slotRoleEditingCanceled(int index,
+ const QByteArray& role,
+ const QVariant& value)
+{
+ m_roleEditor->deleteLater();
+ m_roleEditor = 0;
+ emit roleEditingCanceled(index, role, value);
+ setEditedRole(QByteArray());
+}
+
+void KStandardItemListWidget::slotRoleEditingFinished(int index,
+ const QByteArray& role,
+ const QVariant& value)
+{
+ m_roleEditor->deleteLater();
+ m_roleEditor = 0;
+ emit roleEditingFinished(index, role, value);
+ setEditedRole(QByteArray());
+}
+
+void KStandardItemListWidget::triggerCacheRefreshing()
+{
+ if ((!m_dirtyContent && !m_dirtyLayout) || index() < 0) {
+ return;
+ }
+
+ refreshCache();
+
+ const QHash<QByteArray, QVariant> values = data();
+ m_isExpandable = m_supportsItemExpanding && values["isExpandable"].toBool();
+ m_isHidden = values["text"].toString().startsWith(QLatin1Char('.'));
+
+ updateExpansionArea();
+ updateTextsCache();
+ updatePixmapCache();
+
+ m_dirtyLayout = false;
+ m_dirtyContent = false;
+ m_dirtyContentRoles.clear();
+}
+
+void KStandardItemListWidget::updateExpansionArea()
+{
+ if (m_supportsItemExpanding) {
+ const QHash<QByteArray, QVariant> values = data();
+ Q_ASSERT(values.contains("expandedParentsCount"));
+ const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
+ if (expandedParentsCount >= 0) {
+ const qreal widgetHeight = size().height();
+ const qreal inc = (widgetHeight - KIconLoader::SizeSmall) / 2;
+ const qreal x = expandedParentsCount * widgetHeight + inc;
+ const qreal y = inc;
+ m_expansionArea = QRectF(x, y, KIconLoader::SizeSmall, KIconLoader::SizeSmall);
+ return;
+ }
+ }
+
+ m_expansionArea = QRectF();
+}
+
+void KStandardItemListWidget::updatePixmapCache()
+{
+ // Precondition: Requires already updated m_textPos values to calculate
+ // the remaining height when the alignment is vertical.
+
+ const QSizeF widgetSize = size();
+ const bool iconOnTop = (m_layout == IconsLayout);
+ const KItemListStyleOption& option = styleOption();
+ const qreal padding = option.padding;
+
+ const int maxIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : option.iconSize;
+ const int maxIconHeight = option.iconSize;
+
+ const QHash<QByteArray, QVariant> values = data();
+
+ bool updatePixmap = (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight);
+ if (!updatePixmap && m_dirtyContent) {
+ updatePixmap = m_dirtyContentRoles.isEmpty()
+ || m_dirtyContentRoles.contains("iconPixmap")
+ || m_dirtyContentRoles.contains("iconName")
+ || m_dirtyContentRoles.contains("iconOverlays");
+ }
+
+ if (updatePixmap) {
+ m_pixmap = values["iconPixmap"].value<QPixmap>();
+ if (m_pixmap.isNull()) {
+ // Use the icon that fits to the MIME-type
+ QString iconName = values["iconName"].toString();
+ if (iconName.isEmpty()) {
+ // The icon-name has not been not resolved by KFileItemModelRolesUpdater,
+ // use a generic icon as fallback
+ iconName = QLatin1String("unknown");
+ }
+ m_pixmap = pixmapForIcon(iconName, maxIconHeight);
+ } else if (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight) {
+ // A custom pixmap has been applied. Assure that the pixmap
+ // is scaled to the maximum available size.
+ KPixmapModifier::scale(m_pixmap, QSize(maxIconWidth, maxIconHeight));
+ }
+
+ const QStringList overlays = values["iconOverlays"].toStringList();
+
+ // Strangely KFileItem::overlays() returns empty string-values, so
+ // we need to check first whether an overlay must be drawn at all.
+ // It is more efficient to do it here, as KIconLoader::drawOverlays()
+ // assumes that an overlay will be drawn and has some additional
+ // setup time.
+ foreach (const QString& overlay, overlays) {
+ if (!overlay.isEmpty()) {
+ // There is at least one overlay, draw all overlays above m_pixmap
+ // and cancel the check
+ KIconLoader::global()->drawOverlays(overlays, m_pixmap, KIconLoader::Desktop);
+ break;
+ }
+ }
+
+ if (m_isCut) {
+ applyCutEffect(m_pixmap);
+ }
+
+ if (m_isHidden) {
+ applyHiddenEffect(m_pixmap);
+ }
+ }
+
+ if (!m_overlay.isNull()) {
+ QPainter painter(&m_pixmap);
+ painter.drawPixmap(0, m_pixmap.height() - m_overlay.height(), m_overlay);
+ }
+
+ int scaledIconSize = 0;
+ if (iconOnTop) {
+ const TextInfo* textInfo = m_textInfo.value("text");
+ scaledIconSize = static_cast<int>(textInfo->pos.y() - 2 * padding);
+ } else {
+ const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1;
+ const qreal requiredTextHeight = textRowsCount * option.fontMetrics.height();
+ scaledIconSize = (requiredTextHeight < maxIconHeight) ?
+ widgetSize.height() - 2 * padding : maxIconHeight;
+ }
+
+ const int maxScaledIconWidth = iconOnTop ? widgetSize.width() - 2 * padding : scaledIconSize;
+ const int maxScaledIconHeight = scaledIconSize;
+
+ m_scaledPixmapSize = m_pixmap.size();
+ m_scaledPixmapSize.scale(maxScaledIconWidth, maxScaledIconHeight, Qt::KeepAspectRatio);
+
+ if (iconOnTop) {
+ // Center horizontally and align on bottom within the icon-area
+ m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2);
+ m_pixmapPos.setY(padding + scaledIconSize - m_scaledPixmapSize.height());
+ } else {
+ // Center horizontally and vertically within the icon-area
+ const TextInfo* textInfo = m_textInfo.value("text");
+ m_pixmapPos.setX(textInfo->pos.x() - 2 * padding
+ - (scaledIconSize + m_scaledPixmapSize.width()) / 2);
+ m_pixmapPos.setY(padding
+ + (scaledIconSize - m_scaledPixmapSize.height()) / 2);
+ }
+
+ m_iconRect = QRectF(m_pixmapPos, QSizeF(m_scaledPixmapSize));
+
+ // Prepare the pixmap that is used when the item gets hovered
+ if (isHovered()) {
+ m_hoverPixmap = m_pixmap;
+ KIconEffect* effect = KIconLoader::global()->iconEffect();
+ // In the KIconLoader terminology, active = hover.
+ if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
+ m_hoverPixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState);
+ } else {
+ m_hoverPixmap = m_pixmap;
+ }
+ } else if (hoverOpacity() <= 0.0) {
+ // No hover animation is ongoing. Clear m_hoverPixmap to save memory.
+ m_hoverPixmap = QPixmap();
+ }
+}
+
+void KStandardItemListWidget::updateTextsCache()
+{
+ QTextOption textOption;
+ switch (m_layout) {
+ case IconsLayout:
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ textOption.setAlignment(Qt::AlignHCenter);
+ break;
+ case CompactLayout:
+ case DetailsLayout:
+ textOption.setAlignment(Qt::AlignLeft);
+ textOption.setWrapMode(QTextOption::NoWrap);
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ qDeleteAll(m_textInfo);
+ m_textInfo.clear();
+ for (int i = 0; i < m_sortedVisibleRoles.count(); ++i) {
+ TextInfo* textInfo = new TextInfo();
+ textInfo->staticText.setTextFormat(Qt::PlainText);
+ textInfo->staticText.setPerformanceHint(QStaticText::AggressiveCaching);
+ textInfo->staticText.setTextOption(textOption);
+ m_textInfo.insert(m_sortedVisibleRoles[i], textInfo);
+ }
+
+ switch (m_layout) {
+ case IconsLayout: updateIconsLayoutTextCache(); break;
+ case CompactLayout: updateCompactLayoutTextCache(); break;
+ case DetailsLayout: updateDetailsLayoutTextCache(); break;
+ default: Q_ASSERT(false); break;
+ }
+
+ const TextInfo* ratingTextInfo = m_textInfo.value("rating");
+ if (ratingTextInfo) {
+ // The text of the rating-role has been set to empty to get
+ // replaced by a rating-image showing the rating as stars.
+ const KItemListStyleOption& option = styleOption();
+ QSizeF ratingSize = preferredRatingSize(option);
+
+ const qreal availableWidth = (m_layout == DetailsLayout)
+ ? columnWidth("rating") - columnPadding(option)
+ : m_textRect.width();
+ if (ratingSize.width() > availableWidth) {
+ ratingSize.rwidth() = availableWidth;
+ }
+ m_rating = QPixmap(ratingSize.toSize());
+ m_rating.fill(Qt::transparent);
+
+ QPainter painter(&m_rating);
+ const QRect rect(0, 0, m_rating.width(), m_rating.height());
+ const int rating = data().value("rating").toInt();
+ KRatingPainter::paintRating(&painter, rect, Qt::AlignJustify | Qt::AlignVCenter, rating);
+ } else if (!m_rating.isNull()) {
+ m_rating = QPixmap();
+ }
+}
+
+void KStandardItemListWidget::updateIconsLayoutTextCache()
+{
+ // +------+
+ // | Icon |
+ // +------+
+ //
+ // Name role that
+ // might get wrapped above
+ // several lines.
+ // Additional role 1
+ // Additional role 2
+
+ const QHash<QByteArray, QVariant> values = data();
+
+ const KItemListStyleOption& option = styleOption();
+ const qreal padding = option.padding;
+ const qreal maxWidth = size().width() - 2 * padding;
+ const qreal widgetHeight = size().height();
+ const qreal lineSpacing = option.fontMetrics.lineSpacing();
+
+ // Initialize properties for the "text" role. It will be used as anchor
+ // for initializing the position of the other roles.
+ TextInfo* nameTextInfo = m_textInfo.value("text");
+ const QString nameText = KStringHandler::preProcessWrap(values["text"].toString());
+ nameTextInfo->staticText.setText(nameText);
+
+ // Calculate the number of lines required for the name and the required width
+ qreal nameWidth = 0;
+ qreal nameHeight = 0;
+ QTextLine line;
+
+ const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
+ const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount;
+
+ QTextLayout layout(nameTextInfo->staticText.text(), option.font);
+ layout.setTextOption(nameTextInfo->staticText.textOption());
+ layout.beginLayout();
+ int nameLineIndex = 0;
+ while ((line = layout.createLine()).isValid()) {
+ line.setLineWidth(maxWidth);
+ nameWidth = qMax(nameWidth, line.naturalTextWidth());
+ nameHeight += line.height();
+
+ ++nameLineIndex;
+ if (nameLineIndex == maxNameLines) {
+ // The maximum number of textlines has been reached. If this is
+ // the case provide an elided text if necessary.
+ const int textLength = line.textStart() + line.textLength();
+ if (textLength < nameText.length()) {
+ // Elide the last line of the text
+ QString lastTextLine = nameText.mid(line.textStart(), line.textLength());
+ lastTextLine = option.fontMetrics.elidedText(lastTextLine,
+ Qt::ElideRight,
+ line.naturalTextWidth() - 1);
+ const QString elidedText = nameText.left(line.textStart()) + lastTextLine;
+ nameTextInfo->staticText.setText(elidedText);
+ }
+ break;
+ }
+ }
+ layout.endLayout();
+
+ // Use one line for each additional information
+ nameTextInfo->staticText.setTextWidth(maxWidth);
+ nameTextInfo->pos = QPointF(padding, widgetHeight -
+ nameHeight -
+ additionalRolesCount * lineSpacing -
+ padding);
+ m_textRect = QRectF(padding + (maxWidth - nameWidth) / 2,
+ nameTextInfo->pos.y(),
+ nameWidth,
+ nameHeight);
+
+ // Calculate the position for each additional information
+ qreal y = nameTextInfo->pos.y() + nameHeight;
+ foreach (const QByteArray& role, m_sortedVisibleRoles) {
+ if (role == "text") {
+ continue;
+ }
+
+ const QString text = roleText(role, values);
+ TextInfo* textInfo = m_textInfo.value(role);
+ textInfo->staticText.setText(text);
+
+ qreal requiredWidth = 0;
+
+ QTextLayout layout(text, option.font);
+ QTextOption textOption;
+ textOption.setWrapMode(QTextOption::NoWrap);
+ layout.setTextOption(textOption);
+
+ layout.beginLayout();
+ QTextLine textLine = layout.createLine();
+ if (textLine.isValid()) {
+ textLine.setLineWidth(maxWidth);
+ requiredWidth = textLine.naturalTextWidth();
+ if (requiredWidth > maxWidth) {
+ const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+ textInfo->staticText.setText(elidedText);
+ requiredWidth = option.fontMetrics.width(elidedText);
+ }
+ }
+ layout.endLayout();
+
+ textInfo->pos = QPointF(padding, y);
+ textInfo->staticText.setTextWidth(maxWidth);
+
+ const QRectF textRect(padding + (maxWidth - requiredWidth) / 2, y, requiredWidth, lineSpacing);
+ m_textRect |= textRect;
+
+ y += lineSpacing;
+ }
+
+ // Add a padding to the text rectangle
+ m_textRect.adjust(-padding, -padding, padding, padding);
+}
+
+void KStandardItemListWidget::updateCompactLayoutTextCache()
+{
+ // +------+ Name role
+ // | Icon | Additional role 1
+ // +------+ Additional role 2
+
+ const QHash<QByteArray, QVariant> values = data();
+
+ const KItemListStyleOption& option = styleOption();
+ const qreal widgetHeight = size().height();
+ const qreal lineSpacing = option.fontMetrics.lineSpacing();
+ const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * lineSpacing;
+ const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.padding : option.iconSize;
+
+ qreal maximumRequiredTextWidth = 0;
+ const qreal x = option.padding * 3 + scaledIconSize;
+ qreal y = qRound((widgetHeight - textLinesHeight) / 2);
+ const qreal maxWidth = size().width() - x - option.padding;
+ foreach (const QByteArray& role, m_sortedVisibleRoles) {
+ const QString text = roleText(role, values);
+ TextInfo* textInfo = m_textInfo.value(role);
+ textInfo->staticText.setText(text);
+
+ qreal requiredWidth = option.fontMetrics.width(text);
+ if (requiredWidth > maxWidth) {
+ requiredWidth = maxWidth;
+ const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+ textInfo->staticText.setText(elidedText);
+ }
+
+ textInfo->pos = QPointF(x, y);
+ textInfo->staticText.setTextWidth(maxWidth);
+
+ maximumRequiredTextWidth = qMax(maximumRequiredTextWidth, requiredWidth);
+
+ y += lineSpacing;
+ }
+
+ m_textRect = QRectF(x - option.padding, 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight);
+}
+
+void KStandardItemListWidget::updateDetailsLayoutTextCache()
+{
+ // Precondition: Requires already updated m_expansionArea
+ // to determine the left position.
+
+ // +------+
+ // | Icon | Name role Additional role 1 Additional role 2
+ // +------+
+ m_textRect = QRectF();
+
+ const KItemListStyleOption& option = styleOption();
+ const QHash<QByteArray, QVariant> values = data();
+
+ const qreal widgetHeight = size().height();
+ const int scaledIconSize = widgetHeight - 2 * option.padding;
+ const int fontHeight = option.fontMetrics.height();
+
+ const qreal columnWidthInc = columnPadding(option);
+ qreal firstColumnInc = scaledIconSize;
+ if (m_supportsItemExpanding) {
+ firstColumnInc += (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2;
+ } else {
+ firstColumnInc += option.padding;
+ }
+
+ qreal x = firstColumnInc;
+ const qreal y = qMax(qreal(option.padding), (widgetHeight - fontHeight) / 2);
+
+ foreach (const QByteArray& role, m_sortedVisibleRoles) {
+ QString text = roleText(role, values);
+
+ // Elide the text in case it does not fit into the available column-width
+ qreal requiredWidth = option.fontMetrics.width(text);
+ const qreal roleWidth = columnWidth(role);
+ qreal availableTextWidth = roleWidth - columnWidthInc;
+
+ const bool isTextRole = (role == "text");
+ if (isTextRole) {
+ availableTextWidth -= firstColumnInc;
+ }
+
+ if (requiredWidth > availableTextWidth) {
+ text = option.fontMetrics.elidedText(text, Qt::ElideRight, availableTextWidth);
+ requiredWidth = option.fontMetrics.width(text);
+ }
+
+ TextInfo* textInfo = m_textInfo.value(role);
+ textInfo->staticText.setText(text);
+ textInfo->pos = QPointF(x + columnWidthInc / 2, y);
+ x += roleWidth;
+
+ if (isTextRole) {
+ const qreal textWidth = option.extendedSelectionRegion
+ ? size().width() - textInfo->pos.x()
+ : requiredWidth + 2 * option.padding;
+ m_textRect = QRectF(textInfo->pos.x() - option.padding, 0,
+ textWidth, size().height());
+
+ // The column after the name should always be aligned on the same x-position independent
+ // from the expansion-level shown in the name column
+ x -= firstColumnInc;
+ } else if (isRoleRightAligned(role)) {
+ textInfo->pos.rx() += roleWidth - requiredWidth - columnWidthInc;
+ }
+ }
+}
+
+void KStandardItemListWidget::updateAdditionalInfoTextColor()
+{
+ QColor c1;
+ if (m_customTextColor.isValid()) {
+ c1 = m_customTextColor;
+ } else if (isSelected() && m_layout != DetailsLayout) {
+ c1 = styleOption().palette.highlightedText().color();
+ } else {
+ c1 = styleOption().palette.text().color();
+ }
+
+ // For the color of the additional info the inactive text color
+ // is not used as this might lead to unreadable text for some color schemes. Instead
+ // the text color c1 is slightly mixed with the background color.
+ const QColor c2 = styleOption().palette.base().color();
+ const int p1 = 70;
+ const int p2 = 100 - p1;
+ m_additionalInfoTextColor = QColor((c1.red() * p1 + c2.red() * p2) / 100,
+ (c1.green() * p1 + c2.green() * p2) / 100,
+ (c1.blue() * p1 + c2.blue() * p2) / 100);
+}
+
+void KStandardItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap)
+{
+ if (m_scaledPixmapSize != pixmap.size()) {
+ QPixmap scaledPixmap = pixmap;
+ KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize);
+ painter->drawPixmap(m_pixmapPos, scaledPixmap);
+
+#ifdef KFILEITEMLISTWIDGET_DEBUG
+ painter->setPen(Qt::blue);
+ painter->drawRect(QRectF(m_pixmapPos, QSizeF(m_scaledPixmapSize)));
+#endif
+ } else {
+ painter->drawPixmap(m_pixmapPos, pixmap);
+ }
+}
+
+void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter)
+{
+ const int siblingSize = size().height();
+ const int x = (m_expansionArea.left() + m_expansionArea.right() - siblingSize) / 2;
+ QRect siblingRect(x, 0, siblingSize, siblingSize);
+
+ QStyleOption option;
+ bool isItemSibling = true;
+
+ const QBitArray siblings = siblingsInformation();
+ for (int i = siblings.count() - 1; i >= 0; --i) {
+ option.rect = siblingRect;
+ option.state = siblings.at(i) ? QStyle::State_Sibling : QStyle::State_None;
+
+ if (isItemSibling) {
+ option.state |= QStyle::State_Item;
+ if (m_isExpandable) {
+ option.state |= QStyle::State_Children;
+ }
+ if (data()["isExpanded"].toBool()) {
+ option.state |= QStyle::State_Open;
+ }
+ isItemSibling = false;
+ }
+
+ style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter);
+
+ siblingRect.translate(-siblingRect.width(), 0);
+ }
+}
+
+QRectF KStandardItemListWidget::roleEditingRect(const QByteArray& role) const
+{
+ const TextInfo* textInfo = m_textInfo.value(role);
+ if (!textInfo) {
+ return QRectF();
+ }
+
+ QRectF rect(textInfo->pos, textInfo->staticText.size());
+ if (m_layout == DetailsLayout) {
+ rect.setWidth(columnWidth(role) - rect.x());
+ }
+
+ return rect;
+}
+
+QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, int size)
+{
+ const KIcon icon(name);
+
+ int requestedSize;
+ if (size <= KIconLoader::SizeSmall) {
+ requestedSize = KIconLoader::SizeSmall;
+ } else if (size <= KIconLoader::SizeSmallMedium) {
+ requestedSize = KIconLoader::SizeSmallMedium;
+ } else if (size <= KIconLoader::SizeMedium) {
+ requestedSize = KIconLoader::SizeMedium;
+ } else if (size <= KIconLoader::SizeLarge) {
+ requestedSize = KIconLoader::SizeLarge;
+ } else if (size <= KIconLoader::SizeHuge) {
+ requestedSize = KIconLoader::SizeHuge;
+ } else if (size <= KIconLoader::SizeEnormous) {
+ requestedSize = KIconLoader::SizeEnormous;
+ } else if (size <= KIconLoader::SizeEnormous * 2) {
+ requestedSize = KIconLoader::SizeEnormous * 2;
+ } else {
+ requestedSize = size;
+ }
+
+ QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
+ if (requestedSize != size) {
+ KPixmapModifier::scale(pixmap, QSize(size, size));
+ }
+
+ return pixmap;
+}
+
+void KStandardItemListWidget::applyCutEffect(QPixmap& pixmap)
+{
+ KIconEffect* effect = KIconLoader::global()->iconEffect();
+ pixmap = effect->apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
+}
+
+void KStandardItemListWidget::applyHiddenEffect(QPixmap& pixmap)
+{
+ KIconEffect::semiTransparent(pixmap);
+}
+
+QSizeF KStandardItemListWidget::preferredRatingSize(const KItemListStyleOption& option)
+{
+ const qreal height = option.fontMetrics.ascent();
+ return QSizeF(height * 5, height);
+}
+
+qreal KStandardItemListWidget::columnPadding(const KItemListStyleOption& option)
+{
+ return option.padding * 6;
+}
+
+#include "kstandarditemlistwidget.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#ifndef KSTANDARDITEMLISTWIDGET_H
+#define KSTANDARDITEMLISTWIDGET_H
+
+#include <libdolphin_export.h>
+
+#include <kitemviews/kitemlistwidget.h>
+
+#include <QPixmap>
+#include <QPointF>
+#include <QStaticText>
+
+class KItemListRoleEditor;
+class KItemListStyleOption;
+class KItemListView;
+
+class LIBDOLPHINPRIVATE_EXPORT KStandardItemListWidgetInformant : public KItemListWidgetInformant
+{
+public:
+ KStandardItemListWidgetInformant();
+ virtual ~KStandardItemListWidgetInformant();
+
+ virtual QSizeF itemSizeHint(int index, const KItemListView* view) const;
+
+ virtual qreal preferredRoleColumnWidth(const QByteArray& role,
+ int index,
+ const KItemListView* view) const;
+protected:
+ /**
+ * @return String representation of the role \a role. The representation of
+ * a role might depend on other roles, so the values of all roles
+ * are passed as parameter.
+ */
+ virtual QString roleText(const QByteArray& role,
+ const QHash<QByteArray, QVariant>& values) const;
+
+ friend class KStandardItemListWidget; // Accesses roleText()
+};
+
+/**
+ * @brief Itemlist widget implementation for KStandardItemView and KStandardItemModel.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KStandardItemListWidget : public KItemListWidget
+{
+ Q_OBJECT
+
+public:
+ enum Layout
+ {
+ IconsLayout,
+ CompactLayout,
+ DetailsLayout
+ };
+
+ KStandardItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent);
+ virtual ~KStandardItemListWidget();
+
+ void setLayout(Layout layout);
+ Layout layout() const;
+
+ void setSupportsItemExpanding(bool supportsItemExpanding);
+ bool supportsItemExpanding() const;
+
+ virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
+
+ virtual QRectF iconRect() const;
+ virtual QRectF textRect() const;
+ virtual QRectF textFocusRect() const;
+ virtual QRectF expansionToggleRect() const;
+ virtual QRectF selectionToggleRect() const;
+
+ static KItemListWidgetInformant* createInformant();
+
+protected:
+ /**
+ * Invalidates the cache which results in calling KStandardItemListWidget::refreshCache() as
+ * soon as the item need to gets repainted.
+ */
+ void invalidateCache();
+
+ /**
+ * Is called if the cache got invalidated by KStandardItemListWidget::invalidateCache().
+ * The default implementation is empty.
+ */
+ virtual void refreshCache();
+
+ /**
+ * @return True if the give role should be right aligned when showing it inside a column.
+ * Per default false is returned.
+ */
+ virtual bool isRoleRightAligned(const QByteArray& role) const;
+
+ void setTextColor(const QColor& color);
+ QColor textColor() const;
+
+ void setOverlay(const QPixmap& overlay);
+ QPixmap overlay() const;
+
+ /**
+ * @see KStandardItemListWidgetInformant::roleText().
+ */
+ QString roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values) const;
+
+ virtual void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>());
+ virtual void visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous);
+ virtual void columnWidthChanged(const QByteArray& role, qreal current, qreal previous);
+ virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
+ virtual void hoveredChanged(bool hovered);
+ virtual void selectedChanged(bool selected);
+ virtual void siblingsInformationChanged(const QBitArray& current, const QBitArray& previous);
+ virtual void editedRoleChanged(const QByteArray& current, const QByteArray& previous);
+ virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
+ virtual void showEvent(QShowEvent* event);
+ virtual void hideEvent(QHideEvent* event);
+
+private slots:
+ void slotCutItemsChanged();
+ void slotRoleEditingCanceled(int index, const QByteArray& role, const QVariant& value);
+ void slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value);
+
+private:
+ void triggerCacheRefreshing();
+ void updateExpansionArea();
+ void updatePixmapCache();
+
+ void updateTextsCache();
+ void updateIconsLayoutTextCache();
+ void updateCompactLayoutTextCache();
+ void updateDetailsLayoutTextCache();
+
+ void updateAdditionalInfoTextColor();
+
+ void drawPixmap(QPainter* painter, const QPixmap& pixmap);
+ void drawSiblingsInformation(QPainter* painter);
+
+ QRectF roleEditingRect(const QByteArray &role) const;
+
+ static QPixmap pixmapForIcon(const QString& name, int size);
+ static void applyCutEffect(QPixmap& pixmap);
+ static void applyHiddenEffect(QPixmap& pixmap);
+
+ /**
+ * @return Preferred size of the rating-image based on the given
+ * style-option. The height of the font is taken as
+ * reference.
+ */
+ static QSizeF preferredRatingSize(const KItemListStyleOption& option);
+
+ /**
+ * @return Horizontal padding in pixels that is added to the required width of
+ * a column to display the content.
+ */
+ static qreal columnPadding(const KItemListStyleOption& option);
+
+private:
+ bool m_isCut;
+ bool m_isHidden;
+ bool m_isExpandable;
+ bool m_supportsItemExpanding;
+
+ bool m_dirtyLayout;
+ bool m_dirtyContent;
+ QSet<QByteArray> m_dirtyContentRoles;
+
+ Layout m_layout;
+ QPointF m_pixmapPos;
+ QPixmap m_pixmap;
+ QSize m_scaledPixmapSize;
+
+ QRectF m_iconRect; // Cache for KItemListWidget::iconRect()
+ QPixmap m_hoverPixmap; // Cache for modified m_pixmap when hovering the item
+
+ struct TextInfo
+ {
+ QPointF pos;
+ QStaticText staticText;
+ };
+ QHash<QByteArray, TextInfo*> m_textInfo;
+
+ QRectF m_textRect;
+
+ QList<QByteArray> m_sortedVisibleRoles;
+
+ QRectF m_expansionArea;
+
+ QColor m_customTextColor;
+ QColor m_additionalInfoTextColor;
+
+ QPixmap m_overlay;
+ QPixmap m_rating;
+
+ KItemListRoleEditor* m_roleEditor;
+
+ friend class KStandardItemListWidgetInformant; // Accesses private static methods to be able to
+ // share a common layout calculation
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "kstandarditemmodel.h"
+#include "kstandarditem.h"
+
+KStandardItemModel::KStandardItemModel(QObject* parent) :
+ KItemModelBase(parent),
+ m_items(),
+ m_indexesForItems()
+{
+}
+
+KStandardItemModel::~KStandardItemModel()
+{
+}
+
+void KStandardItemModel::insertItem(int index, KStandardItem* item)
+{
+ if (!m_indexesForItems.contains(item) && !item->m_model) {
+ m_items.insert(index, item);
+ m_indexesForItems.insert(item, index);
+ item->m_model = this;
+ // TODO: no hierarchical items are handled yet
+ }
+}
+
+void KStandardItemModel::appendItem(KStandardItem *item)
+{
+ insertItem(m_items.count(), item);
+}
+
+void KStandardItemModel::removeItem(KStandardItem* item)
+{
+ const int index = m_indexesForItems.value(item, -1);
+ if (index >= 0) {
+ m_items.removeAt(index);
+ m_indexesForItems.remove(item);
+ delete item;
+ // TODO: no hierarchical items are handled yet
+ }
+}
+
+KStandardItem* KStandardItemModel::item(int index) const
+{
+ if (index < 0 || index >= m_items.count()) {
+ return 0;
+ }
+ return m_items[index];
+}
+
+int KStandardItemModel::index(const KStandardItem* item) const
+{
+ return m_indexesForItems.value(item, -1);
+}
+
+int KStandardItemModel::count() const
+{
+ return m_items.count();
+}
+
+QHash<QByteArray, QVariant> KStandardItemModel::data(int index) const
+{
+ // TODO: Ugly hack
+ QHash<QByteArray, QVariant> values;
+ const KStandardItem* item = m_items[index];
+ values.insert("text", item->text());
+ values.insert("iconName", item->icon().name());
+ return values;
+}
+
+bool KStandardItemModel::setData(int index, const QHash<QByteArray, QVariant>& values)
+{
+ Q_UNUSED(values);
+ if (index < 0 || index >= count()) {
+ return false;
+ }
+
+ return true;
+}
+
+QMimeData* KStandardItemModel::createMimeData(const QSet<int>& indexes) const
+{
+ Q_UNUSED(indexes);
+ return 0;
+}
+
+int KStandardItemModel::indexForKeyboardSearch(const QString& text, int startFromIndex) const
+{
+ Q_UNUSED(text);
+ Q_UNUSED(startFromIndex);
+ return -1;
+}
+
+bool KStandardItemModel::supportsDropping(int index) const
+{
+ Q_UNUSED(index);
+ return false;
+}
+
+QString KStandardItemModel::roleDescription(const QByteArray& role) const
+{
+ Q_UNUSED(role);
+ return QString();
+}
+
+QList<QPair<int, QVariant> > KStandardItemModel::groups() const
+{
+ return QList<QPair<int, QVariant> >();
+}
+
+#include "kstandarditemmodel.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#ifndef KSTANDARDITEMMODEL_H
+#define KSTANDARDITEMMODEL_H
+
+#include <libdolphin_export.h>
+#include <kitemviews/kitemmodelbase.h>
+#include <QHash>
+#include <QList>
+
+class KStandardItem;
+
+/**
+ * @brief Model counterpart for KStandardItemView.
+ *
+ * Allows to add items to the model in an easy way by the
+ * class KStandardItem.
+ *
+ * @see KStandardItem
+ */
+class LIBDOLPHINPRIVATE_EXPORT KStandardItemModel : public KItemModelBase
+{
+ Q_OBJECT
+
+public:
+ explicit KStandardItemModel(QObject* parent = 0);
+ virtual ~KStandardItemModel();
+
+ void insertItem(int index, KStandardItem* item);
+ void appendItem(KStandardItem* item);
+ void removeItem(KStandardItem* item);
+ KStandardItem* item(int index) const;
+ int index(const KStandardItem* item) const;
+
+ virtual int count() const;
+ virtual QHash<QByteArray, QVariant> data(int index) const;
+ virtual bool setData(int index, const QHash<QByteArray, QVariant>& values);
+ virtual QMimeData* createMimeData(const QSet<int>& indexes) const;
+ virtual int indexForKeyboardSearch(const QString& text, int startFromIndex = 0) const;
+ virtual bool supportsDropping(int index) const;
+ virtual QString roleDescription(const QByteArray& role) const;
+ virtual QList<QPair<int, QVariant> > groups() const;
+
+private:
+ QList<KStandardItem*> m_items;
+ QHash<const KStandardItem*, int> m_indexesForItems;
+};
+
+#endif
+
+
FoldersPanel::FoldersPanel(QWidget* parent) :
Panel(parent),
m_updateCurrentItem(false),
- m_controller(0)
+ m_controller(0),
+ m_model(0)
{
setLayoutDirection(Qt::LeftToRight);
}
void FoldersPanel::setShowHiddenFiles(bool show)
{
FoldersPanelSettings::setHiddenFilesShown(show);
- fileItemModel()->setShowHiddenFiles(show);
+ m_model->setShowHiddenFiles(show);
}
bool FoldersPanel::showHiddenFiles() const
void FoldersPanel::rename(const KFileItem& item)
{
- const int index = fileItemModel()->index(item);
- m_controller->view()->editRole(index, "name");
+ const int index = m_model->index(item);
+ m_controller->view()->editRole(index, "text");
}
bool FoldersPanel::urlChanged()
}
if (!m_controller) {
- // Postpone the creating of the dir lister to the first show event.
- // This assures that no performance and memory overhead is given when the TreeView is not
- // used at all (see FoldersPanel::setUrl()).
+ // Postpone the creating of the controller to the first show event.
+ // This assures that no performance and memory overhead is given when the folders panel is not
+ // used at all and stays invisible.
KFileItemListView* view = new KFileItemListView();
- view->setWidgetCreator(new KItemListWidgetCreator<KFileItemListWidget>());
-
- KItemListStyleOption styleOption = view->styleOption();
- styleOption.padding = 2;
- styleOption.iconSize = KIconLoader::SizeSmall;
- styleOption.extendedSelectionRegion = true;
- view->setStyleOption(styleOption);
-
- const qreal itemHeight = qMax(int(KIconLoader::SizeSmall), styleOption.fontMetrics.height());
- view->setItemSize(QSizeF(-1, itemHeight + 2 * styleOption.padding));
- view->setItemLayout(KFileItemListView::DetailsLayout);
view->setSupportsItemExpanding(true);
// Set the opacity to 0 initially. The opacity will be increased after the loading of the initial tree
// has been finished in slotLoadingCompleted(). This prevents an unnecessary animation-mess when
connect(view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
- KFileItemModel* model = new KFileItemModel(this);
- model->setShowDirectoriesOnly(true);
- model->setShowHiddenFiles(FoldersPanelSettings::hiddenFilesShown());
+ m_model = new KFileItemModel(this);
+ m_model->setShowDirectoriesOnly(true);
+ m_model->setShowHiddenFiles(FoldersPanelSettings::hiddenFilesShown());
// Use a QueuedConnection to give the view the possibility to react first on the
// finished loading.
- connect(model, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotLoadingCompleted()), Qt::QueuedConnection);
+ connect(m_model, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotLoadingCompleted()), Qt::QueuedConnection);
- KItemListContainer* container = new KItemListContainer(this);
- m_controller = container->controller();
- m_controller->setView(view);
- m_controller->setModel(model);
+ m_controller = new KItemListController(m_model, view, this);
m_controller->setSelectionBehavior(KItemListController::SingleSelection);
m_controller->setAutoActivationDelay(750);
m_controller->setSingleClickActivation(true);
connect(m_controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF)));
connect(m_controller, SIGNAL(itemDropEvent(int,QGraphicsSceneDragDropEvent*)), this, SLOT(slotItemDropEvent(int,QGraphicsSceneDragDropEvent*)));
- // TODO: Check whether it makes sense to make an explicit API for KItemListContainer
- // to make the background transparent.
- container->setFrameShape(QFrame::NoFrame);
- QGraphicsView* graphicsView = qobject_cast<QGraphicsView*>(container->viewport());
- if (graphicsView) {
- // Make the background of the container transparent and apply the window-text color
- // to the text color, so that enough contrast is given for all color
- // schemes
- QPalette p = graphicsView->palette();
- p.setColor(QPalette::Active, QPalette::Text, p.color(QPalette::Active, QPalette::WindowText));
- p.setColor(QPalette::Inactive, QPalette::Text, p.color(QPalette::Inactive, QPalette::WindowText));
- p.setColor(QPalette::Disabled, QPalette::Text, p.color(QPalette::Disabled, QPalette::WindowText));
- graphicsView->setPalette(p);
- graphicsView->viewport()->setAutoFillBackground(false);
- }
+ KItemListContainer* container = new KItemListContainer(m_controller, this);
+ container->setEnabledFrame(false);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(0);
void FoldersPanel::slotItemActivated(int index)
{
- const KFileItem item = fileItemModel()->fileItem(index);
+ const KFileItem item = m_model->fileItem(index);
if (!item.isNull()) {
emit changeUrl(item.url(), Qt::LeftButton);
}
void FoldersPanel::slotItemMiddleClicked(int index)
{
- const KFileItem item = fileItemModel()->fileItem(index);
+ const KFileItem item = m_model->fileItem(index);
if (!item.isNull()) {
emit changeUrl(item.url(), Qt::MiddleButton);
}
{
Q_UNUSED(pos);
- const KFileItem fileItem = fileItemModel()->fileItem(index);
+ const KFileItem fileItem = m_model->fileItem(index);
QWeakPointer<TreeViewContextMenu> contextMenu = new TreeViewContextMenu(this, fileItem);
contextMenu.data()->open();
void FoldersPanel::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
{
if (index >= 0) {
- KFileItem destItem = fileItemModel()->fileItem(index);
+ KFileItem destItem = m_model->fileItem(index);
if (destItem.isNull()) {
return;
}
void FoldersPanel::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value)
{
- if (role == "name") {
- const KFileItem item = fileItemModel()->fileItem(index);
+ if (role == "text") {
+ const KFileItem item = m_model->fileItem(index);
const QString newName = value.toString();
if (!newName.isEmpty() && newName != item.text() && newName != QLatin1String(".") && newName != QLatin1String("..")) {
KonqOperations::rename(this, item.url(), newName);
return;
}
- const int index = fileItemModel()->index(url());
+ const int index = m_model->index(url());
updateCurrentItem(index);
m_updateCurrentItem = false;
}
baseUrl.setPath(QString('/'));
}
- KFileItemModel* model = fileItemModel();
- if (model->directory() != baseUrl) {
+ if (m_model->directory() != baseUrl) {
m_updateCurrentItem = true;
- model->refreshDirectory(baseUrl);
+ m_model->refreshDirectory(baseUrl);
}
- const int index = model->index(url);
+ const int index = m_model->index(url);
if (index >= 0) {
updateCurrentItem(index);
} else {
m_updateCurrentItem = true;
- model->expandParentDirectories(url);
+ m_model->expandParentDirectories(url);
// slotLoadingCompleted() will be invoked after the model has
// expanded the url
}
m_controller->view()->scrollToItem(index);
}
-KFileItemModel* FoldersPanel::fileItemModel() const
-{
- return static_cast<KFileItemModel*>(m_controller->model());
-}
-
#include "folderspanel.moc"
*/
void updateCurrentItem(int index);
- KFileItemModel* fileItemModel() const;
-
private:
bool m_updateCurrentItem;
KItemListController* m_controller;
+ KFileItemModel* m_model;
};
#endif // FOLDERSPANEL_H
/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2008-2012 by Peter Penz <peter.penz19@gmail.com> *
* Copyright (C) 2010 by Christian Muehlhaeuser <muesli@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
#include "placespanel.h"
-#include <KFileItem>
-#include <konq_operations.h>
+#include <KIcon>
+#include <kitemviews/kitemlistcontainer.h>
+#include <kitemviews/kitemlistcontroller.h>
+#include <kitemviews/kstandarditem.h>
+#include <kitemviews/kstandarditemlistview.h>
+#include <kitemviews/kstandarditemmodel.h>
#include <views/draganddrophelper.h>
+#include <QVBoxLayout>
+#include <QShowEvent>
PlacesPanel::PlacesPanel(QWidget* parent) :
- KFilePlacesView(parent),
- m_mouseButtons(Qt::NoButton)
+ Panel(parent),
+ m_controller(0),
+ m_model(0)
{
- setDropOnPlaceEnabled(true);
- connect(this, SIGNAL(urlsDropped(KUrl,QDropEvent*,QWidget*)),
- this, SLOT(slotUrlsDropped(KUrl,QDropEvent*,QWidget*)));
- connect(this, SIGNAL(urlChanged(KUrl)),
- this, SLOT(emitExtendedUrlChangedSignal(KUrl)));
}
PlacesPanel::~PlacesPanel()
{
}
-void PlacesPanel::mousePressEvent(QMouseEvent* event)
+bool PlacesPanel::urlChanged()
{
- m_mouseButtons = event->buttons();
- KFilePlacesView::mousePressEvent(event);
+ return true;
}
-void PlacesPanel::slotUrlsDropped(const KUrl& dest, QDropEvent* event, QWidget* parent)
+void PlacesPanel::showEvent(QShowEvent* event)
{
- Q_UNUSED(parent);
- DragAndDropHelper::dropUrls(KFileItem(), dest, event);
+ if (event->spontaneous()) {
+ Panel::showEvent(event);
+ return;
+ }
+
+ if (!m_controller) {
+ // Postpone the creating of the controller to the first show event.
+ // This assures that no performance and memory overhead is given when the folders panel is not
+ // used at all and stays invisible.
+ KStandardItemListView* view = new KStandardItemListView();
+ m_model = new KStandardItemModel(this);
+ m_model->appendItem(new KStandardItem("Temporary"));
+ m_model->appendItem(new KStandardItem("out of"));
+ m_model->appendItem(new KStandardItem("order. Press"));
+ m_model->appendItem(new KStandardItem("F9 and use"));
+ m_model->appendItem(new KStandardItem("the left icon"));
+ m_model->appendItem(new KStandardItem("of the location"));
+ m_model->appendItem(new KStandardItem("bar instead."));
+
+ m_controller = new KItemListController(m_model, view, this);
+
+ KItemListContainer* container = new KItemListContainer(m_controller, this);
+ container->setEnabledFrame(false);
+
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->addWidget(container);
+ }
+
+ Panel::showEvent(event);
}
-void PlacesPanel::emitExtendedUrlChangedSignal(const KUrl& url)
+void PlacesPanel::slotUrlsDropped(const KUrl& dest, QDropEvent* event, QWidget* parent)
{
- emit urlChanged(url, m_mouseButtons);
+ Q_UNUSED(parent);
+ DragAndDropHelper::dropUrls(KFileItem(), dest, event);
}
#include "placespanel.moc"
/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2008-2012 by Peter Penz <peter.penz19@gmail.com> *
* Copyright (C) 2010 by Christian Muehlhaeuser <muesli@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
#ifndef PLACESPANEL_H
#define PLACESPANEL_H
-#include <kfileplacesview.h>
+#include <panels/panel.h>
+
+class KItemListController;
+class KStandardItemModel;
/**
* @brief Combines bookmarks and mounted devices as list.
*/
-class PlacesPanel : public KFilePlacesView
+class PlacesPanel : public Panel
{
Q_OBJECT
PlacesPanel(QWidget* parent);
virtual ~PlacesPanel();
-signals:
- void urlChanged(const KUrl& url, Qt::MouseButtons buttons);
-
protected:
- virtual void mousePressEvent(QMouseEvent* event);
+ virtual bool urlChanged();
+ virtual void showEvent(QShowEvent* event);
private slots:
void slotUrlsDropped(const KUrl& dest, QDropEvent* event, QWidget* parent);
- void emitExtendedUrlChangedSignal(const KUrl& url);
private:
- Qt::MouseButtons m_mouseButtons;
+ KItemListController* m_controller;
+ KStandardItemModel* m_model;
};
#endif // PLACESPANEL_H
// makes no sense and leads to a usability problem as no viewport area is available
// anymore. Hence as fallback provide at least a size and date column.
visibleRoles.clear();
- visibleRoles.append("name");
+ visibleRoles.append("text");
visibleRoles.append("size");
visibleRoles.append("date");
m_viewProps->setVisibleRoles(visibleRoles);
{
const QSet<QByteArray> roles = m_model->roles();
QCOMPARE(roles.count(), 2);
- QVERIFY(roles.contains("name"));
+ QVERIFY(roles.contains("text"));
QVERIFY(roles.contains("isDir"));
}
void KFileItemModelTest::testDefaultSortRole()
{
- QCOMPARE(m_model->sortRole(), QByteArray("name"));
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
QStringList files;
files << "c.txt" << "a.txt" << "b.txt";
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(m_model->count(), 3);
- QCOMPARE(m_model->data(0)["name"].toString(), QString("a.txt"));
- QCOMPARE(m_model->data(1)["name"].toString(), QString("b.txt"));
- QCOMPARE(m_model->data(2)["name"].toString(), QString("c.txt"));
+ QCOMPARE(m_model->data(0)["text"].toString(), QString("a.txt"));
+ QCOMPARE(m_model->data(1)["text"].toString(), QString("b.txt"));
+ QCOMPARE(m_model->data(2)["text"].toString(), QString("c.txt"));
}
void KFileItemModelTest::testDefaultGroupedSorting()
// Changing the value of a sort-role must result in
// a reordering of the items.
- QCOMPARE(m_model->sortRole(), QByteArray("name"));
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
QStringList files;
files << "a.txt" << "b.txt" << "c.txt";
QDateTime now = QDateTime::currentDateTime();
QSet<QByteArray> roles;
- roles.insert("name");
+ roles.insert("text");
roles.insert("isExpanded");
roles.insert("isExpandable");
roles.insert("expandedParentsCount");
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
// Default: Sort by Name, ascending
- QCOMPARE(m_model->sortRole(), QByteArray("name"));
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
QVERIFY(m_model->sortDirectoriesFirst());
QVERIFY(!m_model->showHiddenFiles());
// Sort by Name, ascending, 'Sort Folders First' disabled
m_model->setSortDirectoriesFirst(false);
- QCOMPARE(m_model->sortRole(), QByteArray("name"));
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e");
QCOMPARE(spyItemsMoved.count(), 1);
// Sort by Name, descending
m_model->setSortDirectoriesFirst(true);
m_model->setSortOrder(Qt::DescendingOrder);
- QCOMPARE(m_model->sortRole(), QByteArray("name"));
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder);
QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "e" << "d" << "b" << "a");
QCOMPARE(spyItemsMoved.count(), 2);
QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1 << 6 << 7);
// Sort by Name, ascending, 'Sort Folders First' disabled
- m_model->setSortRole("name");
+ m_model->setSortRole("text");
QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
QVERIFY(!m_model->sortDirectoriesFirst());
QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e");
{
QStringList items;
for (int i = 0; i < m_model->count(); i++) {
- items << m_model->data(i).value("name").toString();
+ items << m_model->data(i).value("text").toString();
}
return items;
}
const int DefaultTimeout = 2000;
};
-Q_DECLARE_METATYPE(KFileItemListView::Layout);
+Q_DECLARE_METATYPE(KFileItemListView::ItemLayout);
Q_DECLARE_METATYPE(Qt::Orientation);
Q_DECLARE_METATYPE(KItemListController::SelectionBehavior);
Q_DECLARE_METATYPE(QSet<int>);
m_testDir = new TestDir();
m_model = new KFileItemModel();
- m_container = new KItemListContainer();
+ m_view = new KFileItemListView();
+ m_controller = new KItemListController(m_model, m_view, this);
+ m_container = new KItemListContainer(m_controller);
m_controller = m_container->controller();
m_controller->setSelectionBehavior(KItemListController::MultiSelection);
m_selectionManager = m_controller->selectionManager();
- m_view = new KFileItemListView();
- m_controller->setView(m_view);
- m_controller->setModel(m_model);
-
QStringList files;
files
<< "a1" << "a2" << "a3"
void KItemListControllerTest::cleanupTestCase()
{
- delete m_view;
- m_view = 0;
-
delete m_container;
m_container = 0;
- m_controller = 0;
-
- delete m_model;
- m_model = 0;
delete m_testDir;
m_testDir = 0;
*/
void KItemListControllerTest::testKeyboardNavigation_data()
{
- QTest::addColumn<KFileItemListView::Layout>("layout");
+ QTest::addColumn<KFileItemListView::ItemLayout>("layout");
QTest::addColumn<Qt::Orientation>("scrollOrientation");
QTest::addColumn<int>("columnCount");
QTest::addColumn<KItemListController::SelectionBehavior>("selectionBehavior");
QTest::addColumn<bool>("groupingEnabled");
QTest::addColumn<QList<QPair<KeyPress, ViewState> > >("testList");
- QList<KFileItemListView::Layout> layoutList;
- QHash<KFileItemListView::Layout, QString> layoutNames;
+ QList<KFileItemListView::ItemLayout> layoutList;
+ QHash<KFileItemListView::ItemLayout, QString> layoutNames;
layoutList.append(KFileItemListView::IconsLayout);
layoutNames[KFileItemListView::IconsLayout] = "Icons";
layoutList.append(KFileItemListView::CompactLayout);
groupingEnabledList.append(true);
groupingEnabledNames[true] = "grouping enabled";
- foreach (KFileItemListView::Layout layout, layoutList) {
+ foreach (KFileItemListView::ItemLayout layout, layoutList) {
// The following settings depend on the layout.
// Note that 'columns' are actually 'rows' in
// Compact layout.
*/
void KItemListControllerTest::testKeyboardNavigation()
{
- QFETCH(KFileItemListView::Layout, layout);
+ QFETCH(KFileItemListView::ItemLayout, layout);
QFETCH(Qt::Orientation, scrollOrientation);
QFETCH(int, columnCount);
QFETCH(KItemListController::SelectionBehavior, selectionBehavior);
#include <KDebug>
-DolphinFileItemListWidget::DolphinFileItemListWidget(QGraphicsItem* parent) :
- KFileItemListWidget(parent)
+DolphinFileItemListWidget::DolphinFileItemListWidget(KItemListWidgetInformant* informant,
+ QGraphicsItem* parent) :
+ KFileItemListWidget(informant, parent)
{
}
Q_OBJECT
public:
- DolphinFileItemListWidget(QGraphicsItem* parent);
+ DolphinFileItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent);
virtual ~DolphinFileItemListWidget();
protected:
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
-#include "dolphinitemlistcontainer.h"
+#include "dolphinitemlistview.h"
#include "dolphin_generalsettings.h"
#include "dolphin_iconsmodesettings.h"
#include "dolphin_detailsmodesettings.h"
#include "dolphin_compactmodesettings.h"
-
#include "dolphinfileitemlistwidget.h"
#include <kitemviews/kfileitemlistview.h>
#include "zoomlevelinfo.h"
-DolphinItemListContainer::DolphinItemListContainer(QWidget* parent) :
- KItemListContainer(parent),
- m_zoomLevel(0),
- m_fileItemListView(0)
+DolphinItemListView::DolphinItemListView(QGraphicsWidget* parent) :
+ KFileItemListView(parent),
+ m_zoomLevel(0)
{
- controller()->setModel(new KFileItemModel(this));
-
- m_fileItemListView = new KFileItemListView();
- controller()->setView(m_fileItemListView);
-
- m_fileItemListView->setWidgetCreator(new KItemListWidgetCreator<DolphinFileItemListWidget>());
- m_fileItemListView->setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
- m_fileItemListView->setEnlargeSmallPreviews(GeneralSettings::enlargeSmallPreviews());
-
- updateAutoActivationDelay();
updateFont();
updateGridSize();
}
-DolphinItemListContainer::~DolphinItemListContainer()
+DolphinItemListView::~DolphinItemListView()
{
writeSettings();
-
- controller()->setView(0);
- delete m_fileItemListView;
- m_fileItemListView = 0;
-}
-
-void DolphinItemListContainer::setPreviewsShown(bool show)
-{
- beginTransaction();
- m_fileItemListView->setPreviewsShown(show);
- updateGridSize();
- endTransaction();
-}
-
-bool DolphinItemListContainer::previewsShown() const
-{
- return m_fileItemListView->previewsShown();
-}
-
-void DolphinItemListContainer::setVisibleRoles(const QList<QByteArray>& roles)
-{
- m_fileItemListView->setVisibleRoles(roles);
- updateGridSize();
-}
-
-QList<QByteArray> DolphinItemListContainer::visibleRoles() const
-{
- return m_fileItemListView->visibleRoles();
}
-void DolphinItemListContainer::setZoomLevel(int level)
+void DolphinItemListView::setZoomLevel(int level)
{
if (level < ZoomLevelInfo::minimumLevel()) {
level = ZoomLevelInfo::minimumLevel();
updateGridSize();
}
-int DolphinItemListContainer::zoomLevel() const
+int DolphinItemListView::zoomLevel() const
{
return m_zoomLevel;
}
-void DolphinItemListContainer::setItemLayout(KFileItemListView::Layout layout)
-{
- if (layout == itemLayout()) {
- return;
- }
-
- beginTransaction();
- m_fileItemListView->setItemLayout(layout);
-
- switch (layout) {
- case KFileItemListView::IconsLayout:
- m_fileItemListView->setScrollOrientation(Qt::Vertical);
- m_fileItemListView->setHeaderVisible(false);
- m_fileItemListView->setSupportsItemExpanding(false);
- break;
- case KFileItemListView::DetailsLayout:
- m_fileItemListView->setScrollOrientation(Qt::Vertical);
- m_fileItemListView->setHeaderVisible(true);
- m_fileItemListView->setSupportsItemExpanding(DetailsModeSettings::expandableFolders());
-
- break;
- case KFileItemListView::CompactLayout:
- m_fileItemListView->setScrollOrientation(Qt::Horizontal);
- m_fileItemListView->setHeaderVisible(false);
- m_fileItemListView->setSupportsItemExpanding(false);
- break;
- default:
- Q_ASSERT(false);
- break;
- }
-
- updateFont();
- updateGridSize();
- endTransaction();
-}
-
-KFileItemListView::Layout DolphinItemListContainer::itemLayout() const
-{
- return m_fileItemListView->itemLayout();
-}
-
-void DolphinItemListContainer::beginTransaction()
-{
- m_fileItemListView->beginTransaction();
-}
-
-void DolphinItemListContainer::endTransaction()
-{
- m_fileItemListView->endTransaction();
-}
-
-void DolphinItemListContainer::readSettings()
+void DolphinItemListView::readSettings()
{
ViewModeSettings settings(viewMode());
settings.readConfig();
beginTransaction();
- m_fileItemListView->setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
+ setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
const bool expandableFolders = (itemLayout() && KFileItemListView::DetailsLayout) &&
DetailsModeSettings::expandableFolders();
- m_fileItemListView->setSupportsItemExpanding(expandableFolders);
+ setSupportsItemExpanding(expandableFolders);
- updateAutoActivationDelay();
updateFont();
updateGridSize();
<< "directorythumbnail"
<< "imagethumbnail"
<< "jpegthumbnail");
- m_fileItemListView->setEnabledPlugins(plugins);
+ setEnabledPlugins(plugins);
endTransaction();
}
-void DolphinItemListContainer::writeSettings()
+void DolphinItemListView::writeSettings()
{
IconsModeSettings::self()->writeConfig();
CompactModeSettings::self()->writeConfig();
DetailsModeSettings::self()->writeConfig();
}
-void DolphinItemListContainer::updateGridSize()
+KItemListWidgetCreatorBase* DolphinItemListView::defaultWidgetCreator() const
+{
+ return new KItemListWidgetCreator<DolphinFileItemListWidget>();
+}
+
+void DolphinItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous)
+{
+ Q_UNUSED(previous);
+
+ if (current == DetailsLayout) {
+ setSupportsItemExpanding(DetailsModeSettings::expandableFolders());
+ setHeaderVisible(true);
+ } else {
+ setHeaderVisible(false);
+ }
+
+ updateFont();
+ updateGridSize();
+}
+
+void DolphinItemListView::onPreviewsShownChanged(bool shown)
+{
+ Q_UNUSED(shown);
+ updateGridSize();
+}
+
+void DolphinItemListView::onVisibleRolesChanged(const QList<QByteArray>& current,
+ const QList<QByteArray>& previous)
+{
+ KFileItemListView::onVisibleRolesChanged(current, previous);
+ updateGridSize();
+}
+
+void DolphinItemListView::updateGridSize()
{
const ViewModeSettings settings(viewMode());
// Calculate the size of the icon
const int iconSize = previewsShown() ? settings.previewSize() : settings.iconSize();
m_zoomLevel = ZoomLevelInfo::zoomLevelForIconSize(QSize(iconSize, iconSize));
- KItemListStyleOption styleOption = m_fileItemListView->styleOption();
+ KItemListStyleOption option = styleOption();
const int padding = 2;
int horizontalMargin = 0;
itemWidth = iconSize + padding * 2;
}
- itemHeight = padding * 3 + iconSize + styleOption.fontMetrics.lineSpacing();
+ itemHeight = padding * 3 + iconSize + option.fontMetrics.lineSpacing();
if (IconsModeSettings::maximumTextLines() > 0) {
// A restriction is given for the maximum number of textlines (0 means
// having no restriction)
- const int additionalInfoCount = m_fileItemListView->visibleRoles().count() - 1;
+ const int additionalInfoCount = visibleRoles().count() - 1;
const int maxAdditionalLines = additionalInfoCount + IconsModeSettings::maximumTextLines();
- maxTextSize.rheight() = styleOption.fontMetrics.lineSpacing() * maxAdditionalLines;
+ maxTextSize.rheight() = option.fontMetrics.lineSpacing() * maxAdditionalLines;
}
horizontalMargin = 4;
break;
}
case KFileItemListView::CompactLayout: {
- itemWidth = padding * 4 + iconSize + styleOption.fontMetrics.height() * 5;
- const int textLinesCount = m_fileItemListView->visibleRoles().count();
- itemHeight = padding * 2 + qMax(iconSize, textLinesCount * styleOption.fontMetrics.lineSpacing());
+ itemWidth = padding * 4 + iconSize + option.fontMetrics.height() * 5;
+ const int textLinesCount = visibleRoles().count();
+ itemHeight = padding * 2 + qMax(iconSize, textLinesCount * option.fontMetrics.lineSpacing());
if (CompactModeSettings::maximumTextWidthIndex() > 0) {
// A restriction is given for the maximum width of the text (0 means
// having no restriction)
- maxTextSize.rwidth() = styleOption.fontMetrics.height() * 10 *
+ maxTextSize.rwidth() = option.fontMetrics.height() * 10 *
CompactModeSettings::maximumTextWidthIndex();
}
}
case KFileItemListView::DetailsLayout: {
itemWidth = -1;
- itemHeight = padding * 2 + qMax(iconSize, styleOption.fontMetrics.lineSpacing());
+ itemHeight = padding * 2 + qMax(iconSize, option.fontMetrics.lineSpacing());
break;
}
default:
}
// Apply the calculated values
- styleOption.padding = padding;
- styleOption.horizontalMargin = horizontalMargin;
- styleOption.verticalMargin = verticalMargin;
- styleOption.iconSize = iconSize;
- styleOption.maxTextSize = maxTextSize;
- m_fileItemListView->beginTransaction();
- m_fileItemListView->setStyleOption(styleOption);
- m_fileItemListView->setItemSize(QSizeF(itemWidth, itemHeight));
- m_fileItemListView->endTransaction();
+ option.padding = padding;
+ option.horizontalMargin = horizontalMargin;
+ option.verticalMargin = verticalMargin;
+ option.iconSize = iconSize;
+ option.maxTextSize = maxTextSize;
+ beginTransaction();
+ setStyleOption(option);
+ setItemSize(QSizeF(itemWidth, itemHeight));
+ endTransaction();
}
-void DolphinItemListContainer::updateFont()
+void DolphinItemListView::updateFont()
{
- KItemListStyleOption styleOption = m_fileItemListView->styleOption();
+ KItemListStyleOption option = styleOption();
const ViewModeSettings settings(viewMode());
font.setWeight(settings.fontWeight());
font.setPointSizeF(settings.fontSize());
- styleOption.font = font;
- styleOption.fontMetrics = QFontMetrics(font);
-
- m_fileItemListView->setStyleOption(styleOption);
-}
+ option.font = font;
+ option.fontMetrics = QFontMetrics(font);
-void DolphinItemListContainer::updateAutoActivationDelay()
-{
- const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
- controller()->setAutoActivationDelay(delay);
+ setStyleOption(option);
}
-ViewModeSettings::ViewMode DolphinItemListContainer::viewMode() const
+ViewModeSettings::ViewMode DolphinItemListView::viewMode() const
{
ViewModeSettings::ViewMode mode;
return mode;
}
-#include "dolphinitemlistcontainer.moc"
+#include "dolphinitemlistview.moc"
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
-#ifndef DOLPHINITEMLISTCONTAINER_H
-#define DOLPHINITEMLISTCONTAINER_H
+#ifndef DOLPHINITEMLISTVIEW_H
+#define DOLPHINITEMLISTVIEW_H
#include <kitemviews/kfileitemlistview.h>
-#include <kitemviews/kitemlistcontainer.h>
#include <settings/viewmodes/viewmodesettings.h>
#include <libdolphin_export.h>
class KFileItemListView;
/**
- * @brief Extends KItemListContainer by Dolphin specific properties.
+ * @brief Dolphin specific view-implementation.
*
- * The view and model for KFileItems are created automatically when
- * instantating KItemListContainer.
- *
- * The Dolphin settings of the icons-, compact- and details-view are
- * converted internally to properties that can be used to configure e.g.
- * the item-size and visible roles of the KItemListView.
+ * Offers zoom-level support and takes care for translating
+ * the view-properties into the corresponding KItemListView
+ * properties.
*/
-class LIBDOLPHINPRIVATE_EXPORT DolphinItemListContainer : public KItemListContainer
+class LIBDOLPHINPRIVATE_EXPORT DolphinItemListView : public KFileItemListView
{
Q_OBJECT
public:
- explicit DolphinItemListContainer(QWidget* parent = 0);
-
- virtual ~DolphinItemListContainer();
-
- void setPreviewsShown(bool show);
- bool previewsShown() const;
-
- void setVisibleRoles(const QList<QByteArray>& roles);
- QList<QByteArray> visibleRoles() const;
+ explicit DolphinItemListView(QGraphicsWidget* parent = 0);
+ virtual ~DolphinItemListView();
void setZoomLevel(int level);
int zoomLevel() const;
- void setItemLayout(KFileItemListView::Layout layout);
- KFileItemListView::Layout itemLayout() const;
-
- void beginTransaction();
- void endTransaction();
-
void readSettings();
void writeSettings();
+protected:
+ virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const;
+ virtual void onItemLayoutChanged(ItemLayout current, ItemLayout previous);
+ virtual void onPreviewsShownChanged(bool shown);
+ virtual void onVisibleRolesChanged(const QList<QByteArray>& current,
+ const QList<QByteArray>& previous);
+
private:
void updateGridSize();
void updateFont();
- /**
- * Updates the auto activation delay of the itemlist controller
- * dependent on the 'autoExpand' setting from the general settings.
- */
- void updateAutoActivationDelay();
-
ViewModeSettings::ViewMode viewMode() const;
private:
int m_zoomLevel;
- KFileItemListView* m_fileItemListView;
};
#endif
#include <KLocale>
#include <kitemviews/kfileitemmodel.h>
#include <kitemviews/kfileitemlistview.h>
+#include <kitemviews/kitemlistcontainer.h>
#include <kitemviews/kitemlistheader.h>
#include <kitemviews/kitemlistselectionmanager.h>
#include <kitemviews/kitemlistview.h>
#include "dolphinnewfilemenuobserver.h"
#include "dolphin_detailsmodesettings.h"
#include "dolphin_generalsettings.h"
-#include "dolphinitemlistcontainer.h"
+#include "dolphinitemlistview.h"
#include "draganddrophelper.h"
#include "renamedialog.h"
#include "versioncontrol/versioncontrolobserver.h"
m_mode(DolphinView::IconsView),
m_visibleRoles(),
m_topLayout(0),
+ m_model(0),
+ m_view(0),
m_container(0),
m_toolTipManager(0),
m_selectionChangedTimer(0),
connect(m_selectionChangedTimer, SIGNAL(timeout()),
this, SLOT(emitSelectionChangedSignal()));
- m_container = new DolphinItemListContainer(this);
- m_container->setVisibleRoles(QList<QByteArray>() << "name");
+ m_model = new KFileItemModel(this);
+ m_view = new DolphinItemListView();
+ m_view->setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
+ m_view->setEnlargeSmallPreviews(GeneralSettings::enlargeSmallPreviews());
+ m_view->setVisibleRoles(QList<QByteArray>() << "text");
+ applyModeToView();
+
+ KItemListController* controller = new KItemListController(m_model, m_view, this);
+ const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
+ controller->setAutoActivationDelay(delay);
+
+ m_container = new KItemListContainer(controller, this);
m_container->installEventFilter(this);
setFocusProxy(m_container);
connect(m_container->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip()));
connect(m_container->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip()));
- KItemListController* controller = m_container->controller();
controller->setSelectionBehavior(KItemListController::MultiSelection);
connect(controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int)));
connect(controller, SIGNAL(itemsActivated(QSet<int>)), this, SLOT(slotItemsActivated(QSet<int>)));
connect(controller, SIGNAL(itemDropEvent(int,QGraphicsSceneDragDropEvent*)), this, SLOT(slotItemDropEvent(int,QGraphicsSceneDragDropEvent*)));
connect(controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)), this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
- KFileItemModel* model = fileItemModel();
- connect(model, SIGNAL(directoryLoadingStarted()), this, SLOT(slotDirectoryLoadingStarted()));
- connect(model, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
- connect(model, SIGNAL(directoryLoadingProgress(int)), this, SIGNAL(directoryLoadingProgress(int)));
- connect(model, SIGNAL(directorySortingProgress(int)), this, SIGNAL(directorySortingProgress(int)));
- connect(model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ connect(m_model, SIGNAL(directoryLoadingStarted()), this, SLOT(slotDirectoryLoadingStarted()));
+ connect(m_model, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
+ connect(m_model, SIGNAL(directoryLoadingProgress(int)), this, SIGNAL(directoryLoadingProgress(int)));
+ connect(m_model, SIGNAL(directorySortingProgress(int)), this, SIGNAL(directorySortingProgress(int)));
+ connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
this, SLOT(slotItemsChanged()));
- connect(model, SIGNAL(itemsRemoved(KItemRangeList)), this, SIGNAL(itemCountChanged()));
- connect(model, SIGNAL(itemsInserted(KItemRangeList)), this, SIGNAL(itemCountChanged()));
- connect(model, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString)));
- connect(model, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)));
- connect(model, SIGNAL(directoryRedirection(KUrl,KUrl)), this, SLOT(slotDirectoryRedirection(KUrl,KUrl)));
-
- KItemListView* view = controller->view();
- view->installEventFilter(this);
- connect(view, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
+ connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)), this, SIGNAL(itemCountChanged()));
+ connect(m_model, SIGNAL(itemsInserted(KItemRangeList)), this, SIGNAL(itemCountChanged()));
+ connect(m_model, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString)));
+ connect(m_model, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)));
+ connect(m_model, SIGNAL(directoryRedirection(KUrl,KUrl)), this, SLOT(slotDirectoryRedirection(KUrl,KUrl)));
+
+ m_view->installEventFilter(this);
+ connect(m_view, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
this, SLOT(slotSortOrderChangedByHeader(Qt::SortOrder,Qt::SortOrder)));
- connect(view, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
+ connect(m_view, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
this, SLOT(slotSortRoleChangedByHeader(QByteArray,QByteArray)));
- connect(view, SIGNAL(visibleRolesChanged(QList<QByteArray>,QList<QByteArray>)),
+ connect(m_view, SIGNAL(visibleRolesChanged(QList<QByteArray>,QList<QByteArray>)),
this, SLOT(slotVisibleRolesChangedByHeader(QList<QByteArray>,QList<QByteArray>)));
- connect(view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ connect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
- connect(view->header(), SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)),
+ connect(m_view->header(), SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)),
this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal)));
KItemListSelectionManager* selectionManager = controller->selectionManager();
m_toolTipManager = new ToolTipManager(this);
m_versionControlObserver = new VersionControlObserver(this);
- m_versionControlObserver->setModel(model);
+ m_versionControlObserver->setModel(m_model);
connect(m_versionControlObserver, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString)));
connect(m_versionControlObserver, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)));
connect(m_versionControlObserver, SIGNAL(operationCompletedMessage(QString)), this, SIGNAL(operationCompletedMessage(QString)));
ViewProperties props(url());
props.setPreviewsShown(show);
- m_container->setPreviewsShown(show);
+ m_view->setPreviewsShown(show);
emit previewsShownChanged(show);
}
bool DolphinView::previewsShown() const
{
- return m_container->previewsShown();
+ return m_view->previewsShown();
}
void DolphinView::setHiddenFilesShown(bool show)
{
- KFileItemModel* model = fileItemModel();
- if (model->showHiddenFiles() == show) {
+ if (m_model->showHiddenFiles() == show) {
return;
}
ViewProperties props(url());
props.setHiddenFilesShown(show);
- model->setShowHiddenFiles(show);
+ m_model->setShowHiddenFiles(show);
emit hiddenFilesShownChanged(show);
}
bool DolphinView::hiddenFilesShown() const
{
- return fileItemModel()->showHiddenFiles();
+ return m_model->showHiddenFiles();
}
void DolphinView::setGroupedSorting(bool grouped)
bool DolphinView::groupedSorting() const
{
- return fileItemModel()->groupedSorting();
+ return m_model->groupedSorting();
}
KFileItemList DolphinView::items() const
{
KFileItemList list;
- const KFileItemModel* model = fileItemModel();
- const int itemCount = model->count();
+ const int itemCount = m_model->count();
list.reserve(itemCount);
for (int i = 0; i < itemCount; ++i) {
- list.append(model->fileItem(i));
+ list.append(m_model->fileItem(i));
}
return list;
int DolphinView::itemsCount() const
{
- return fileItemModel()->count();
+ return m_model->count();
}
KFileItemList DolphinView::selectedItems() const
{
- const KFileItemModel* model = fileItemModel();
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
const QSet<int> selectedIndexes = selectionManager->selectedItems();
QSetIterator<int> it(selectedIndexes);
while (it.hasNext()) {
const int index = it.next();
- selectedItems.append(model->fileItem(index));
+ selectedItems.append(m_model->fileItem(index));
}
return selectedItems;
}
const KItemListSelectionManager::SelectionMode mode = enabled
? KItemListSelectionManager::Select
: KItemListSelectionManager::Deselect;
- const KFileItemModel* model = fileItemModel();
KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- for (int index = 0; index < model->count(); index++) {
- const KFileItem item = model->fileItem(index);
+ for (int index = 0; index < m_model->count(); index++) {
+ const KFileItem item = m_model->fileItem(index);
if (pattern.exactMatch(item.text())) {
// An alternative approach would be to store the matching items in a QSet<int> and
// select them in one go after the loop, but we'd need a new function
void DolphinView::setZoomLevel(int level)
{
const int oldZoomLevel = zoomLevel();
- m_container->setZoomLevel(level);
+ m_view->setZoomLevel(level);
if (zoomLevel() != oldZoomLevel) {
emit zoomLevelChanged(zoomLevel(), oldZoomLevel);
}
int DolphinView::zoomLevel() const
{
- return m_container->zoomLevel();
+ return m_view->zoomLevel();
}
void DolphinView::setSortRole(const QByteArray& role)
Qt::SortOrder DolphinView::sortOrder() const
{
- KItemModelBase* model = fileItemModel();
- return model->sortOrder();
+ return m_model->sortOrder();
}
void DolphinView::setSortFoldersFirst(bool foldersFirst)
bool DolphinView::sortFoldersFirst() const
{
- KFileItemModel* model = fileItemModel();
- return model->sortDirectoriesFirst();
+ return m_model->sortDirectoriesFirst();
}
void DolphinView::setVisibleRoles(const QList<QByteArray>& roles)
props.setVisibleRoles(roles);
m_visibleRoles = roles;
- m_container->setVisibleRoles(roles);
+ m_view->setVisibleRoles(roles);
emit visibleRolesChanged(m_visibleRoles, previousRoles);
}
void DolphinView::stopLoading()
{
- fileItemModel()->cancelDirectoryLoading();
+ m_model->cancelDirectoryLoading();
}
void DolphinView::readSettings()
{
- const int oldZoomLevel = m_container->zoomLevel();
+ const int oldZoomLevel = m_view->zoomLevel();
GeneralSettings::self()->readConfig();
- m_container->readSettings();
+ m_view->readSettings();
applyViewProperties();
- const int newZoomLevel = m_container->zoomLevel();
+ const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
+ m_container->controller()->setAutoActivationDelay(delay);
+
+ const int newZoomLevel = m_view->zoomLevel();
if (newZoomLevel != oldZoomLevel) {
emit zoomLevelChanged(newZoomLevel, oldZoomLevel);
}
void DolphinView::writeSettings()
{
GeneralSettings::self()->writeConfig();
- m_container->writeSettings();
+ m_view->writeSettings();
}
void DolphinView::setNameFilter(const QString& nameFilter)
{
- fileItemModel()->setNameFilter(nameFilter);
+ m_model->setNameFilter(nameFilter);
}
QString DolphinView::nameFilter() const
{
- return fileItemModel()->nameFilter();
+ return m_model->nameFilter();
}
QString DolphinView::statusBarText() const
QList<QAction*> actions;
if (items.isEmpty()) {
- const KFileItem item = fileItemModel()->rootItem();
+ const KFileItem item = m_model->rootItem();
actions = m_versionControlObserver->actions(KFileItemList() << item);
} else {
actions = m_versionControlObserver->actions(items);
// applying the view properties, otherwise expensive operations
// might be done on the existing items although they get cleared
// anyhow afterwards by loadDirectory().
- fileItemModel()->clear();
+ m_model->clear();
applyViewProperties();
loadDirectory(url);
void DolphinView::selectAll()
{
KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- selectionManager->setSelected(0, fileItemModel()->count());
+ selectionManager->setSelected(0, m_model->count());
}
void DolphinView::invertSelection()
{
KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- selectionManager->setSelected(0, fileItemModel()->count(), KItemListSelectionManager::Toggle);
+ selectionManager->setSelected(0, m_model->count(), KItemListSelectionManager::Toggle);
}
void DolphinView::clearSelection()
}
if (items.count() == 1) {
- const int index = fileItemModel()->index(items.first());
- m_container->controller()->view()->editRole(index, "name");
+ const int index = m_model->index(items.first());
+ m_container->controller()->view()->editRole(index, "text");
} else {
RenameDialog* dialog = new RenameDialog(this, items);
dialog->setAttribute(Qt::WA_DeleteOnClose);
break;
case QEvent::GraphicsSceneDragEnter:
- if (watched == m_container->controller()->view()) {
+ if (watched == m_view) {
m_dragging = true;
}
break;
case QEvent::GraphicsSceneDragLeave:
- if (watched == m_container->controller()->view()) {
+ if (watched == m_view) {
m_dragging = false;
}
break;
case QEvent::GraphicsSceneDrop:
- if (watched == m_container->controller()->view()) {
+ if (watched == m_view) {
m_dragging = false;
}
default:
void DolphinView::slotItemActivated(int index)
{
- const KFileItem item = fileItemModel()->fileItem(index);
+ const KFileItem item = m_model->fileItem(index);
if (!item.isNull()) {
emit itemActivated(item);
}
KFileItemList items;
- KFileItemModel* model = fileItemModel();
QSetIterator<int> it(indexes);
while (it.hasNext()) {
const int index = it.next();
- items.append(model->fileItem(index));
+ items.append(m_model->fileItem(index));
}
foreach (const KFileItem& item, items) {
void DolphinView::slotItemMiddleClicked(int index)
{
- const KFileItem item = fileItemModel()->fileItem(index);
+ const KFileItem item = m_model->fileItem(index);
if (item.isDir() || isTabsForFilesEnabled()) {
emit tabRequested(item.url());
}
void DolphinView::slotItemContextMenuRequested(int index, const QPointF& pos)
{
- const KFileItem item = fileItemModel()->fileItem(index);
+ const KFileItem item = m_model->fileItem(index);
emit requestContextMenu(pos.toPoint(), item, url(), QList<QAction*>());
}
// Add all roles to the menu that can be shown or hidden by the user
const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
foreach (const KFileItemModel::RoleInfo& info, rolesInfo) {
- if (info.role == "name") {
- // It should not be possible to hide the "name" role
+ if (info.role == "text") {
+ // It should not be possible to hide the "text" role
continue;
}
- const QString text = fileItemModel()->roleDescription(info.role);
+ const QString text = m_model->roleDescription(info.role);
QAction* action = 0;
if (info.group.isEmpty()) {
action = menu->addAction(text);
{
Q_UNUSED(previous);
- const QList<QByteArray> visibleRoles = m_container->visibleRoles();
+ const QList<QByteArray> visibleRoles = m_view->visibleRoles();
ViewProperties props(url());
QList<int> columnWidths = props.headerColumnWidths();
if (columnWidths.count() != visibleRoles.count()) {
columnWidths.clear();
columnWidths.reserve(visibleRoles.count());
- const KItemListHeader* header = m_container->controller()->view()->header();
+ const KItemListHeader* header = m_view->header();
foreach (const QByteArray& role, visibleRoles) {
const int width = header->columnWidth(role);
columnWidths.append(width);
void DolphinView::slotItemHovered(int index)
{
- const KFileItem item = fileItemModel()->fileItem(index);
+ const KFileItem item = m_model->fileItem(index);
if (GeneralSettings::showToolTips() && !m_dragging) {
QRectF itemRect = m_container->controller()->view()->itemContextRect(index);
void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
{
KUrl destUrl;
- KFileItem destItem = fileItemModel()->fileItem(index);
+ KFileItem destItem = m_model->fileItem(index);
if (destItem.isNull() || (!destItem.isDir() && !destItem.isDesktopFile())) {
// Use the URL of the view as drop target if the item is no directory
// or desktop-file
- destItem = fileItemModel()->rootItem();
+ destItem = m_model->rootItem();
destUrl = url();
} else {
// The item represents a directory or desktop-file
{
if (previous != 0) {
disconnect(previous, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
+ m_versionControlObserver->setModel(0);
}
- Q_ASSERT(qobject_cast<KFileItemModel*>(current));
- connect(current, SIGNAL(loadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
+ if (current) {
+ Q_ASSERT(qobject_cast<KFileItemModel*>(current));
+ connect(current, SIGNAL(loadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
- KFileItemModel* fileItemModel = static_cast<KFileItemModel*>(current);
- m_versionControlObserver->setModel(fileItemModel);
+ KFileItemModel* fileItemModel = static_cast<KFileItemModel*>(current);
+ m_versionControlObserver->setModel(fileItemModel);
+ }
}
void DolphinView::slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons)
ViewProperties props(url());
props.setSortOrder(order);
- KItemModelBase* model = fileItemModel();
- model->setSortOrder(order);
+ m_model->setSortOrder(order);
emit sortOrderChanged(order);
}
ViewProperties props(url());
props.setSortFoldersFirst(foldersFirst);
- KFileItemModel* model = fileItemModel();
- model->setSortDirectoriesFirst(foldersFirst);
+ m_model->setSortDirectoriesFirst(foldersFirst);
emit sortFoldersFirstChanged(foldersFirst);
}
// Restore expanded folders (only relevant for the details view - will be ignored by the view in other view modes)
QSet<KUrl> urls;
stream >> urls;
- fileItemModel()->restoreExpandedDirectories(urls);
+ m_model->restoreExpandedDirectories(urls);
}
void DolphinView::saveState(QDataStream& stream)
// Save the current item that has the keyboard focus
const int currentIndex = m_container->controller()->selectionManager()->currentItem();
if (currentIndex != -1) {
- KFileItem item = fileItemModel()->fileItem(currentIndex);
+ KFileItem item = m_model->fileItem(currentIndex);
Q_ASSERT(!item.isNull()); // If the current index is valid a item must exist
KUrl currentItemUrl = item.url();
stream << currentItemUrl;
stream << QPoint(x, y);
// Save expanded folders (only relevant for the details view - the set will be empty in other view modes)
- stream << fileItemModel()->expandedDirectories();
+ stream << m_model->expandedDirectories();
}
KFileItem DolphinView::rootItem() const
{
- return fileItemModel()->rootItem();
+ return m_model->rootItem();
}
void DolphinView::observeCreatedItem(const KUrl& url)
{
if (m_currentItemUrl != KUrl()) {
KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- const int currentIndex = fileItemModel()->index(m_currentItemUrl);
+ const int currentIndex = m_model->index(m_currentItemUrl);
if (currentIndex != -1) {
selectionManager->setCurrentItem(currentIndex);
} else {
KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
QSet<int> selectedItems = selectionManager->selectedItems();
- const KFileItemModel* model = fileItemModel();
foreach (const KUrl& url, m_selectedUrls) {
- const int index = model->index(url);
+ const int index = m_model->index(url);
if (index >= 0) {
selectedItems.insert(index);
}
int& folderCount,
KIO::filesize_t& totalFileSize) const
{
- const KFileItemModel* model = fileItemModel();
- const int itemCount = model->count();
+ const int itemCount = m_model->count();
for (int i = 0; i < itemCount; ++i) {
- const KFileItem item = model->fileItem(i);
+ const KFileItem item = m_model->fileItem(i);
if (item.isDir()) {
++folderCount;
} else {
void DolphinView::slotSortOrderChangedByHeader(Qt::SortOrder current, Qt::SortOrder previous)
{
Q_UNUSED(previous);
- Q_ASSERT(fileItemModel()->sortOrder() == current);
+ Q_ASSERT(m_model->sortOrder() == current);
ViewProperties props(url());
props.setSortOrder(current);
void DolphinView::slotSortRoleChangedByHeader(const QByteArray& current, const QByteArray& previous)
{
Q_UNUSED(previous);
- Q_ASSERT(fileItemModel()->sortRole() == current);
+ Q_ASSERT(m_model->sortRole() == current);
ViewProperties props(url());
props.setSortRole(current);
void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value)
{
- if (role == "name") {
- const KFileItem item = fileItemModel()->fileItem(index);
+ if (role == "text") {
+ const KFileItem item = m_model->fileItem(index);
const QString newName = value.toString();
if (!newName.isEmpty() && newName != item.text() && newName != QLatin1String(".") && newName != QLatin1String("..")) {
KonqOperations::rename(this, item.url(), newName);
}
}
-KFileItemModel* DolphinView::fileItemModel() const
-{
- return static_cast<KFileItemModel*>(m_container->controller()->model());
-}
-
void DolphinView::loadDirectory(const KUrl& url, bool reload)
{
if (!url.isValid()) {
return;
}
- KFileItemModel* model = fileItemModel();
if (reload) {
- model->refreshDirectory(url);
+ m_model->refreshDirectory(url);
} else {
- model->loadDirectory(url);
+ m_model->loadDirectory(url);
}
}
void DolphinView::applyViewProperties()
{
- m_container->beginTransaction();
+ m_view->beginTransaction();
const ViewProperties props(url());
- KFileItemModel* model = fileItemModel();
const Mode mode = props.viewMode();
if (m_mode != mode) {
// Changing the mode might result in changing
// the zoom level. Remember the old zoom level so
// that zoomLevelChanged() can get emitted.
- const int oldZoomLevel = m_container->zoomLevel();
-
- switch (m_mode) {
- case IconsView: m_container->setItemLayout(KFileItemListView::IconsLayout); break;
- case CompactView: m_container->setItemLayout(KFileItemListView::CompactLayout); break;
- case DetailsView: m_container->setItemLayout(KFileItemListView::DetailsLayout); break;
- default: Q_ASSERT(false); break;
- }
+ const int oldZoomLevel = m_view->zoomLevel();
+ applyModeToView();
emit modeChanged(m_mode, previousMode);
- if (m_container->zoomLevel() != oldZoomLevel) {
- emit zoomLevelChanged(m_container->zoomLevel(), oldZoomLevel);
+ if (m_view->zoomLevel() != oldZoomLevel) {
+ emit zoomLevelChanged(m_view->zoomLevel(), oldZoomLevel);
}
}
const bool hiddenFilesShown = props.hiddenFilesShown();
- if (hiddenFilesShown != model->showHiddenFiles()) {
- model->setShowHiddenFiles(hiddenFilesShown);
+ if (hiddenFilesShown != m_model->showHiddenFiles()) {
+ m_model->setShowHiddenFiles(hiddenFilesShown);
emit hiddenFilesShownChanged(hiddenFilesShown);
}
const bool groupedSorting = props.groupedSorting();
- if (groupedSorting != model->groupedSorting()) {
- model->setGroupedSorting(groupedSorting);
+ if (groupedSorting != m_model->groupedSorting()) {
+ m_model->setGroupedSorting(groupedSorting);
emit groupedSortingChanged(groupedSorting);
}
const QByteArray sortRole = props.sortRole();
- if (sortRole != model->sortRole()) {
- model->setSortRole(sortRole);
+ if (sortRole != m_model->sortRole()) {
+ m_model->setSortRole(sortRole);
emit sortRoleChanged(sortRole);
}
const Qt::SortOrder sortOrder = props.sortOrder();
- if (sortOrder != model->sortOrder()) {
- model->setSortOrder(sortOrder);
+ if (sortOrder != m_model->sortOrder()) {
+ m_model->setSortOrder(sortOrder);
emit sortOrderChanged(sortOrder);
}
const bool sortFoldersFirst = props.sortFoldersFirst();
- if (sortFoldersFirst != model->sortDirectoriesFirst()) {
- model->setSortDirectoriesFirst(sortFoldersFirst);
+ if (sortFoldersFirst != m_model->sortDirectoriesFirst()) {
+ m_model->setSortDirectoriesFirst(sortFoldersFirst);
emit sortFoldersFirstChanged(sortFoldersFirst);
}
if (visibleRoles != m_visibleRoles) {
const QList<QByteArray> previousVisibleRoles = m_visibleRoles;
m_visibleRoles = visibleRoles;
- m_container->setVisibleRoles(visibleRoles);
+ m_view->setVisibleRoles(visibleRoles);
emit visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
}
const bool previewsShown = props.previewsShown();
- if (previewsShown != m_container->previewsShown()) {
+ if (previewsShown != m_view->previewsShown()) {
const int oldZoomLevel = zoomLevel();
- m_container->setPreviewsShown(previewsShown);
+ m_view->setPreviewsShown(previewsShown);
emit previewsShownChanged(previewsShown);
// Changing the preview-state might result in a changed zoom-level
}
}
- m_container->endTransaction();
+ m_view->endTransaction();
+}
+
+void DolphinView::applyModeToView()
+{
+ switch (m_mode) {
+ case IconsView: m_view->setItemLayout(KFileItemListView::IconsLayout); break;
+ case CompactView: m_view->setItemLayout(KFileItemListView::CompactLayout); break;
+ case DetailsView: m_view->setItemLayout(KFileItemListView::DetailsLayout); break;
+ default: Q_ASSERT(false); break;
+ }
}
void DolphinView::pasteToUrl(const KUrl& url)
QMimeData* DolphinView::selectionMimeData() const
{
- const KFileItemModel* model = fileItemModel();
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
const QSet<int> selectedIndexes = selectionManager->selectedItems();
- return model->createMimeData(selectedIndexes);
+ return m_model->createMimeData(selectedIndexes);
}
void DolphinView::markPastedUrlsAsSelected(const QMimeData* mimeData)
const bool wasFolderWritable = m_isFolderWritable;
m_isFolderWritable = true;
- const KFileItem item = fileItemModel()->rootItem();
+ const KFileItem item = m_model->rootItem();
if (!item.isNull()) {
KFileItemListProperties capabilities(KFileItemList() << item);
m_isFolderWritable = capabilities.supportsWriting();
typedef KIO::FileUndoManager::CommandType CommandType;
-class DolphinItemListContainer;
+class DolphinItemListView;
class KAction;
class KActionCollection;
class KFileItemModel;
+class KItemListContainer;
class KItemModelBase;
class KUrl;
class ToolTipManager;
void calculateItemCount(int& fileCount, int& folderCount, KIO::filesize_t& totalFileSize) const;
private:
- KFileItemModel* fileItemModel() const;
-
void loadDirectory(const KUrl& url, bool reload = false);
/**
*/
void applyViewProperties();
+ /**
+ * Applies the m_mode property to the corresponding
+ * itemlayout-property of the KItemListView.
+ */
+ void applyModeToView();
+
/**
* Helper method for DolphinView::paste() and DolphinView::pasteIntoFolder().
* Pastes the clipboard data into the URL \a url.
QVBoxLayout* m_topLayout;
- DolphinItemListContainer* m_container;
+ KFileItemModel* m_model;
+ DolphinItemListView* m_view;
+ KItemListContainer* m_container;
ToolTipManager* m_toolTipManager;
const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
foreach (const KFileItemModel::RoleInfo& info, rolesInfo) {
- if (!isSortGroup && info.role == "name") {
- // It should not be possible to hide the "name" role
+ if (!isSortGroup && info.role == "text") {
+ // It should not be possible to hide the "text" role
continue;
}
#include <QFileInfo>
namespace {
- const int CurrentViewPropertiesVersion = 2;
const int AdditionalInfoViewPropertiesVersion = 1;
+ const int NameRolePropertiesVersion = 2;
+ const int CurrentViewPropertiesVersion = 3;
// String representation to mark the additional properties of
// the details view as customized by the user. See
// is accepted.
QList<QByteArray> roles;
- roles.append("name");
+ roles.append("text");
// Iterate through all stored keys and append all roles that match to
// the curren view mode.
const int prefixLength = prefix.length();
QStringList visibleRoles = m_node->visibleRoles();
- if (visibleRoles.isEmpty() && m_node->version() <= AdditionalInfoViewPropertiesVersion) {
+ const int version = m_node->version();
+ if (visibleRoles.isEmpty() && version <= AdditionalInfoViewPropertiesVersion) {
// Convert the obsolete additionalInfo-property from older versions into the
// visibleRoles-property
visibleRoles = const_cast<ViewProperties*>(this)->convertAdditionalInfo();
+ } else if (version <= NameRolePropertiesVersion) {
+ visibleRoles = const_cast<ViewProperties*>(this)->convertNameRole();
}
foreach (const QString& visibleRole, visibleRoles) {
if (visibleRole.startsWith(prefix)) {
const QByteArray role = visibleRole.right(visibleRole.length() - prefixLength).toLatin1();
- if (role != "name") {
+ if (role != "text") {
roles.append(role);
}
}
// For the details view the size and date should be shown per default
// until the additional information has been explicitly changed by the user
- const bool useDefaultValues = roles.count() == 1 // "name"
+ const bool useDefaultValues = roles.count() == 1 // "text"
&& (m_node->viewMode() == DolphinView::DetailsView)
&& !visibleRoles.contains(CustomizedDetailsString);
if (useDefaultValues) {
return visibleRoles;
}
+QStringList ViewProperties::convertNameRole()
+{
+ QStringList visibleRoles = m_node->visibleRoles();
+ for (int i = 0; i < visibleRoles.count(); ++i) {
+ if (visibleRoles[i].endsWith("_name")) {
+ const int leftLength = visibleRoles[i].length() - 5;
+ visibleRoles[i] = visibleRoles[i].left(leftLength) + "_text";
+ }
+ }
+
+ m_node->setVisibleRoles(visibleRoles);
+ update();
+
+ return visibleRoles;
+}
+
+
bool ViewProperties::isPartOfHome(const QString& filePath)
{
// For performance reasons cache the path in a static QString
/**
* Provides backward compatibility with .directory files created with
- * Dolphin < 2.1: Converts the old additionalInfo-property into
+ * Dolphin < 2.0: Converts the old additionalInfo-property into
* the visibleRoles-property and clears the additionalInfo-property.
*/
QStringList convertAdditionalInfo();
+ /**
+ * Provides backward compatibility with .directory files created with
+ * Dolphin < 2.1: Converts the old name-role "name" to the generic
+ * role "text".
+ */
+ QStringList convertNameRole();
+
/**
* Returns true, if \a filePath is part of the home-path (see QDir::homePath()).
*/