]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kfileitemlistwidget.cpp
Version control: Apply text-color if an item is versioned
[dolphin.git] / src / kitemviews / kfileitemlistwidget.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "kfileitemlistwidget.h"
21
22 #include "kfileitemmodel.h"
23 #include "kitemlistview.h"
24 #include "kpixmapmodifier_p.h"
25
26 #include <KIcon>
27 #include <KIconEffect>
28 #include <KIconLoader>
29 #include <KLocale>
30 #include <KStringHandler>
31 #include <KDebug>
32
33 #include <QFontMetricsF>
34 #include <QGraphicsSceneResizeEvent>
35 #include <QPainter>
36 #include <QStyleOption>
37 #include <QTextLayout>
38 #include <QTextLine>
39
40 //#define KFILEITEMLISTWIDGET_DEBUG
41
42 KFileItemListWidget::KFileItemListWidget(QGraphicsItem* parent) :
43 KItemListWidget(parent),
44 m_isDir(false),
45 m_dirtyLayout(true),
46 m_dirtyContent(true),
47 m_dirtyContentRoles(),
48 m_layout(IconsLayout),
49 m_pixmapPos(),
50 m_pixmap(),
51 m_scaledPixmapSize(),
52 m_hoverPixmapRect(),
53 m_hoverPixmap(),
54 m_textPos(),
55 m_text(),
56 m_textBoundingRect(),
57 m_sortedVisibleRoles(),
58 m_expansionArea(),
59 m_customTextColor(0),
60 m_additionalInfoTextColor()
61 {
62 for (int i = 0; i < TextIdCount; ++i) {
63 m_text[i].setTextFormat(Qt::PlainText);
64 m_text[i].setPerformanceHint(QStaticText::AggressiveCaching);
65 }
66 }
67
68 KFileItemListWidget::~KFileItemListWidget()
69 {
70 delete m_customTextColor;
71 m_customTextColor = 0;
72 }
73
74 void KFileItemListWidget::setLayout(Layout layout)
75 {
76 if (m_layout != layout) {
77 m_layout = layout;
78 m_dirtyLayout = true;
79 update();
80 }
81 }
82
83 KFileItemListWidget::Layout KFileItemListWidget::layout() const
84 {
85 return m_layout;
86 }
87
88 void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
89 {
90 KItemListWidget::paint(painter, option, widget);
91
92 const_cast<KFileItemListWidget*>(this)->updateCache();
93
94 // Draw expansion toggle '>' or 'V'
95 if (m_isDir && !m_expansionArea.isEmpty()) {
96 QStyleOption arrowOption;
97 arrowOption.rect = m_expansionArea.toRect();
98 const QStyle::PrimitiveElement arrow = data()["isExpanded"].toBool()
99 ? QStyle::PE_IndicatorArrowDown : QStyle::PE_IndicatorArrowRight;
100 style()->drawPrimitive(arrow, &arrowOption, painter);
101 }
102
103 const KItemListStyleOption& itemListStyleOption = styleOption();
104 if (isHovered()) {
105 // Blend the unhovered and hovered pixmap if the hovering
106 // animation is ongoing
107 if (hoverOpacity() < 1.0) {
108 drawPixmap(painter, m_pixmap);
109 }
110
111 const qreal opacity = painter->opacity();
112 painter->setOpacity(hoverOpacity() * opacity);
113 drawPixmap(painter, m_hoverPixmap);
114 painter->setOpacity(opacity);
115 } else {
116 drawPixmap(painter, m_pixmap);
117 }
118
119 painter->setFont(itemListStyleOption.font);
120 if (m_customTextColor) {
121 painter->setPen(*m_customTextColor);
122 } else {
123 painter->setPen(itemListStyleOption.palette.text().color());
124 }
125 painter->drawStaticText(m_textPos[Name], m_text[Name]);
126
127 painter->setPen(m_additionalInfoTextColor);
128 painter->setFont(itemListStyleOption.font);
129 for (int i = Name + 1; i < TextIdCount; ++i) {
130 painter->drawStaticText(m_textPos[i], m_text[i]);
131 }
132
133 #ifdef KFILEITEMLISTWIDGET_DEBUG
134 painter->setPen(Qt::red);
135 painter->setBrush(Qt::NoBrush);
136 painter->drawText(QPointF(0, itemListStyleOption.fontMetrics.height()), QString::number(index()));
137 painter->drawRect(rect());
138 #endif
139 }
140
141 QRectF KFileItemListWidget::iconBoundingRect() const
142 {
143 const_cast<KFileItemListWidget*>(this)->updateCache();
144
145 QRectF bounds = m_hoverPixmapRect;
146 const qreal margin = styleOption().margin;
147 bounds.adjust(-margin, -margin, margin, margin);
148 return bounds;
149 }
150
151 QRectF KFileItemListWidget::textBoundingRect() const
152 {
153 const_cast<KFileItemListWidget*>(this)->updateCache();
154 return m_textBoundingRect;
155 }
156
157 QRectF KFileItemListWidget::expansionToggleRect() const
158 {
159 const_cast<KFileItemListWidget*>(this)->updateCache();
160 return m_isDir ? m_expansionArea : QRectF();
161 }
162
163 void KFileItemListWidget::setTextColor(const QColor& color)
164 {
165 if (color.isValid()) {
166 if (!m_customTextColor) {
167 m_customTextColor = new QColor(color);
168 } else {
169 *m_customTextColor = color;
170 }
171 updateAdditionalInfoTextColor();
172 update();
173 } else if (m_customTextColor){
174 delete m_customTextColor;
175 m_customTextColor = 0;
176 updateAdditionalInfoTextColor();
177 update();
178 }
179 }
180
181 QColor KFileItemListWidget::textColor() const
182 {
183 return m_customTextColor ? *m_customTextColor : styleOption().palette.text().color();
184 }
185
186 void KFileItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
187 const QSet<QByteArray>& roles)
188 {
189 KItemListWidget::dataChanged(current, roles);
190 m_dirtyContent = true;
191
192 QSet<QByteArray> dirtyRoles;
193 if (roles.isEmpty()) {
194 dirtyRoles = visibleRoles().keys().toSet();
195 dirtyRoles.insert("iconPixmap");
196 dirtyRoles.insert("iconName");
197 } else {
198 dirtyRoles = roles;
199 }
200
201 QSetIterator<QByteArray> it(dirtyRoles);
202 while (it.hasNext()) {
203 const QByteArray& role = it.next();
204 m_dirtyContentRoles.insert(role);
205 }
206 }
207
208 void KFileItemListWidget::visibleRolesChanged(const QHash<QByteArray, int>& current,
209 const QHash<QByteArray, int>& previous)
210 {
211 KItemListWidget::visibleRolesChanged(current, previous);
212 m_dirtyLayout = true;
213
214 // Cache the roles sorted into m_sortedVisibleRoles:
215 const int visibleRolesCount = current.count();
216 m_sortedVisibleRoles.clear();
217 m_sortedVisibleRoles.reserve(visibleRolesCount);
218 for (int i = 0; i < visibleRolesCount; ++i) {
219 m_sortedVisibleRoles.append(QByteArray());
220 }
221
222 QHashIterator<QByteArray, int> it(current);
223 while (it.hasNext()) {
224 it.next();
225
226 const int index = it.value();
227 if (index < 0 || index >= visibleRolesCount || !m_sortedVisibleRoles.at(index).isEmpty()) {
228 kWarning() << "The visible roles have an invalid sort order.";
229 break;
230 }
231
232 const QByteArray& role = it.key();
233 m_sortedVisibleRoles[index] = role;
234 }
235 }
236
237 void KFileItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
238 const QHash<QByteArray, QSizeF>& previous)
239 {
240 KItemListWidget::visibleRolesSizesChanged(current, previous);
241 m_dirtyLayout = true;
242 }
243
244 void KFileItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
245 const KItemListStyleOption& previous)
246 {
247 KItemListWidget::styleOptionChanged(current, previous);
248 updateAdditionalInfoTextColor();
249 m_dirtyLayout = true;
250 }
251
252 void KFileItemListWidget::hoveredChanged(bool hovered)
253 {
254 Q_UNUSED(hovered);
255 m_dirtyLayout = true;
256 }
257
258 void KFileItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
259 {
260 KItemListWidget::resizeEvent(event);
261 m_dirtyLayout = true;
262 }
263
264 void KFileItemListWidget::updateCache()
265 {
266 if ((!m_dirtyContent && !m_dirtyLayout) || index() < 0) {
267 return;
268 }
269
270 m_isDir = data()["isDir"].toBool();
271
272 updateExpansionArea();
273 updateTextsCache();
274 updatePixmapCache();
275
276 m_dirtyLayout = false;
277 m_dirtyContent = false;
278 m_dirtyContentRoles.clear();
279 }
280
281 void KFileItemListWidget::updateExpansionArea()
282 {
283 if (m_layout == DetailsLayout) {
284 const QHash<QByteArray, QVariant> values = data();
285 Q_ASSERT(values.contains("expansionLevel"));
286 const KItemListStyleOption& option = styleOption();
287 const int expansionLevel = values.value("expansionLevel", 0).toInt();
288
289 const qreal widgetHeight = size().height();
290 const qreal expansionLevelSize = KIconLoader::SizeSmall;
291 const qreal x = option.margin + expansionLevel * widgetHeight;
292 const qreal y = (widgetHeight - expansionLevelSize) / 2;
293 m_expansionArea = QRectF(x, y, expansionLevelSize, expansionLevelSize);
294 } else {
295 m_expansionArea = QRectF();
296 }
297 }
298
299 void KFileItemListWidget::updatePixmapCache()
300 {
301 // Precondition: Requires already updated m_textPos values to calculate
302 // the remaining height when the alignment is vertical.
303
304 const bool iconOnTop = (m_layout == IconsLayout);
305 const KItemListStyleOption& option = styleOption();
306 const int iconHeight = option.iconSize;
307
308 const QHash<QByteArray, QVariant> values = data();
309 const QSizeF widgetSize = size();
310
311 int scaledIconHeight = 0;
312 if (iconOnTop) {
313 scaledIconHeight = static_cast<int>(m_textPos[Name].y() - 3 * option.margin);
314 } else {
315 const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1;
316 const qreal requiredTextHeight = textRowsCount * option.fontMetrics.height();
317 scaledIconHeight = (requiredTextHeight < iconHeight) ? widgetSize.height() - 2 * option.margin : iconHeight;
318 }
319
320 bool updatePixmap = (iconHeight != m_pixmap.height());
321 if (!updatePixmap && m_dirtyContent) {
322 updatePixmap = m_dirtyContentRoles.isEmpty()
323 || m_dirtyContentRoles.contains("iconPixmap")
324 || m_dirtyContentRoles.contains("iconName");
325 }
326
327 if (updatePixmap) {
328 m_pixmap = values["iconPixmap"].value<QPixmap>();
329 if (m_pixmap.isNull()) {
330 // Use the icon that fits to the MIME-type
331 QString iconName = values["iconName"].toString();
332 if (iconName.isEmpty()) {
333 // The icon-name has not been not resolved by KFileItemModelRolesUpdater,
334 // use a generic icon as fallback
335 iconName = QLatin1String("unknown");
336 }
337 m_pixmap = pixmapForIcon(iconName, iconHeight);
338 m_hoverPixmapRect.setSize(m_pixmap.size());
339 } else if (m_pixmap.size() != QSize(iconHeight, iconHeight)) {
340 // A custom pixmap has been applied. Assure that the pixmap
341 // is scaled to the available size.
342 const bool scale = m_pixmap.width() > iconHeight || m_pixmap.height() > iconHeight ||
343 (m_pixmap.width() < iconHeight && m_pixmap.height() < iconHeight);
344 if (scale) {
345 KPixmapModifier::scale(m_pixmap, QSize(iconHeight, iconHeight));
346 }
347 m_hoverPixmapRect.setSize(m_pixmap.size());
348
349 // To simplify the handling of scaling the original pixmap
350 // will be embedded into a square pixmap.
351 QPixmap squarePixmap(iconHeight, iconHeight);
352 squarePixmap.fill(Qt::transparent);
353
354 QPainter painter(&squarePixmap);
355 if (iconOnTop) {
356 const int x = (iconHeight - m_pixmap.width()) / 2; // Center horizontally
357 const int y = iconHeight - m_pixmap.height(); // Align on bottom
358 painter.drawPixmap(x, y, m_pixmap);
359 } else {
360 const int x = iconHeight - m_pixmap.width(); // Align right
361 const int y = (iconHeight - m_pixmap.height()) / 2; // Center vertically
362 painter.drawPixmap(x, y, m_pixmap);
363 }
364
365 m_pixmap = squarePixmap;
366 } else {
367 m_hoverPixmapRect.setSize(m_pixmap.size());
368 }
369
370 Q_ASSERT(m_pixmap.height() == iconHeight);
371 }
372
373 m_scaledPixmapSize = QSize(scaledIconHeight, scaledIconHeight);
374
375 if (iconOnTop) {
376 m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2);
377 } else {
378 m_pixmapPos.setX(m_textPos[Name].x() - 2 * option.margin - scaledIconHeight);
379 }
380 m_pixmapPos.setY(option.margin);
381
382 // Center the hover rectangle horizontally and align it on bottom
383 const qreal x = m_pixmapPos.x() + (m_scaledPixmapSize.width() - m_hoverPixmapRect.width()) / 2.0;
384 const qreal y = m_pixmapPos.y() + m_scaledPixmapSize.height() - m_hoverPixmapRect.height();
385 m_hoverPixmapRect.moveTopLeft(QPointF(x, y));
386
387 // Prepare the pixmap that is used when the item gets hovered
388 if (isHovered()) {
389 m_hoverPixmap = m_pixmap;
390 KIconEffect* effect = KIconLoader::global()->iconEffect();
391 // In the KIconLoader terminology, active = hover.
392 if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
393 m_hoverPixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState);
394 } else {
395 m_hoverPixmap = m_pixmap;
396 }
397 } else if (hoverOpacity() <= 0.0) {
398 // No hover animation is ongoing. Clear m_hoverPixmap to save memory.
399 m_hoverPixmap = QPixmap();
400 }
401 }
402
403 void KFileItemListWidget::updateTextsCache()
404 {
405 QTextOption textOption;
406 switch (m_layout) {
407 case IconsLayout:
408 textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
409 textOption.setAlignment(Qt::AlignHCenter);
410 break;
411 case CompactLayout:
412 case DetailsLayout:
413 textOption.setAlignment(Qt::AlignLeft);
414 textOption.setWrapMode(QTextOption::NoWrap);
415 break;
416 default:
417 Q_ASSERT(false);
418 break;
419 }
420
421 for (int i = 0; i < TextIdCount; ++i) {
422 m_text[i].setText(QString());
423 m_text[i].setTextOption(textOption);
424 }
425
426 switch (m_layout) {
427 case IconsLayout: updateIconsLayoutTextCache(); break;
428 case CompactLayout: updateCompactLayoutTextCache(); break;
429 case DetailsLayout: updateDetailsLayoutTextCache(); break;
430 default: Q_ASSERT(false); break;
431 }
432 }
433
434 void KFileItemListWidget::updateIconsLayoutTextCache()
435 {
436 // +------+
437 // | Icon |
438 // +------+
439 //
440 // Name role that
441 // might get wrapped above
442 // several lines.
443 // Additional role 1
444 // Additional role 2
445
446 const QHash<QByteArray, QVariant> values = data();
447
448 const KItemListStyleOption& option = styleOption();
449 const qreal maxWidth = size().width() - 2 * option.margin;
450 const qreal widgetHeight = size().height();
451 const qreal fontHeight = option.fontMetrics.height();
452
453 // Initialize properties for the "name" role. It will be used as anchor
454 // for initializing the position of the other roles.
455 m_text[Name].setText(KStringHandler::preProcessWrap(values["name"].toString()));
456
457 // Calculate the number of lines required for the name and the required width
458 int textLinesCountForName = 0;
459 qreal requiredWidthForName = 0;
460 QTextLine line;
461
462 QTextLayout layout(m_text[Name].text(), option.font);
463 layout.setTextOption(m_text[Name].textOption());
464 layout.beginLayout();
465 while ((line = layout.createLine()).isValid()) {
466 line.setLineWidth(maxWidth);
467 requiredWidthForName = qMax(requiredWidthForName, line.naturalTextWidth());
468 ++textLinesCountForName;
469 }
470 layout.endLayout();
471
472 // Use one line for each additional information
473 int textLinesCount = textLinesCountForName;
474 const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
475 textLinesCount += additionalRolesCount;
476
477 m_text[Name].setTextWidth(maxWidth);
478 m_textPos[Name] = QPointF(option.margin, widgetHeight - textLinesCount * fontHeight - option.margin);
479 m_textBoundingRect = QRectF(option.margin + (maxWidth - requiredWidthForName) / 2,
480 m_textPos[Name].y(),
481 requiredWidthForName,
482 m_text[Name].size().height());
483
484 // Calculate the position for each additional information
485 qreal y = m_textPos[Name].y() + textLinesCountForName * fontHeight;
486 foreach (const QByteArray& role, m_sortedVisibleRoles) {
487 const TextId textId = roleTextId(role);
488 if (textId == Name) {
489 continue;
490 }
491
492 const QString text = roleText(textId, values[role]);
493 m_text[textId].setText(text);
494
495 qreal requiredWidth = 0;
496
497 QTextLayout layout(text, option.font);
498 layout.setTextOption(m_text[textId].textOption());
499 layout.beginLayout();
500 QTextLine textLine = layout.createLine();
501 if (textLine.isValid()) {
502 textLine.setLineWidth(maxWidth);
503 requiredWidth = textLine.naturalTextWidth();
504 if (textLine.textLength() < text.length()) {
505 // TODO: QFontMetrics::elidedText() works different regarding the given width
506 // in comparison to QTextLine::setLineWidth(). It might happen that the text does
507 // not get elided although it does not fit into the given width. As workaround
508 // the margin is substracted.
509 const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth - option.margin);
510 m_text[textId].setText(elidedText);
511 }
512 }
513 layout.endLayout();
514
515 m_textPos[textId] = QPointF(option.margin, y);
516 m_text[textId].setTextWidth(maxWidth);
517
518 const QRectF textBoundingRect(option.margin + (maxWidth - requiredWidth) / 2, y, requiredWidth, fontHeight);
519 m_textBoundingRect |= textBoundingRect;
520
521 y += fontHeight;
522 }
523
524 // Add a margin to the text bounding rectangle
525 const qreal margin = option.margin;
526 m_textBoundingRect.adjust(-margin, -margin, margin, margin);
527 }
528
529 void KFileItemListWidget::updateCompactLayoutTextCache()
530 {
531 // +------+ Name role
532 // | Icon | Additional role 1
533 // +------+ Additional role 2
534
535 const QHash<QByteArray, QVariant> values = data();
536
537 const KItemListStyleOption& option = styleOption();
538 const qreal widgetHeight = size().height();
539 const qreal fontHeight = option.fontMetrics.height();
540 const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * fontHeight;
541 const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.margin : option.iconSize;
542
543 qreal maximumRequiredTextWidth = 0;
544 const qreal x = option.margin * 3 + scaledIconSize;
545 qreal y = (widgetHeight - textLinesHeight) / 2;
546 const qreal maxWidth = size().width() - x - option.margin;
547 foreach (const QByteArray& role, m_sortedVisibleRoles) {
548 const TextId textId = roleTextId(role);
549
550 const QString text = roleText(textId, values[role]);
551 m_text[textId].setText(text);
552
553 qreal requiredWidth = option.fontMetrics.width(text);
554 if (requiredWidth > maxWidth) {
555 requiredWidth = maxWidth;
556 const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
557 m_text[textId].setText(elidedText);
558 }
559
560 m_textPos[textId] = QPointF(x, y);
561 m_text[textId].setTextWidth(maxWidth);
562
563 maximumRequiredTextWidth = qMax(maximumRequiredTextWidth, requiredWidth);
564
565 y += fontHeight;
566 }
567
568 m_textBoundingRect = QRectF(x - option.margin, 0, maximumRequiredTextWidth + 2 * option.margin, widgetHeight);
569 }
570
571 void KFileItemListWidget::updateDetailsLayoutTextCache()
572 {
573 // Precondition: Requires already updated m_expansionArea
574 // to determine the left position.
575
576 // +------+
577 // | Icon | Name role Additional role 1 Additional role 2
578 // +------+
579 m_textBoundingRect = QRectF();
580
581 const KItemListStyleOption& option = styleOption();
582 const QHash<QByteArray, QVariant> values = data();
583
584 const qreal widgetHeight = size().height();
585 const int scaledIconSize = widgetHeight - 2 * option.margin;
586 const int fontHeight = option.fontMetrics.height();
587
588 qreal x = m_expansionArea.right() + option.margin * 3 + scaledIconSize;
589 const qreal y = qMax(qreal(option.margin), (widgetHeight - fontHeight) / 2);
590
591 foreach (const QByteArray& role, m_sortedVisibleRoles) {
592 const TextId textId = roleTextId(role);
593
594 const QString text = roleText(textId, values[role]);
595 m_text[textId].setText(text);
596
597 const qreal requiredWidth = option.fontMetrics.width(text);
598 m_textPos[textId] = QPointF(x, y);
599
600 const qreal columnWidth = visibleRolesSizes().value(role, QSizeF(0, 0)).width();
601 x += columnWidth;
602
603 switch (textId) {
604 case Name: {
605 m_textBoundingRect = QRectF(m_textPos[textId].x() - option.margin, 0,
606 requiredWidth + 2 * option.margin, size().height());
607
608 // The column after the name should always be aligned on the same x-position independent
609 // from the expansion-level shown in the name column
610 x -= m_expansionArea.right();
611 break;
612 }
613 case Size:
614 // The values for the size should be right aligned
615 m_textPos[textId].rx() += columnWidth - requiredWidth - 2 * option.margin;
616 break;
617
618 default:
619 break;
620 }
621 }
622 }
623
624 void KFileItemListWidget::updateAdditionalInfoTextColor()
625 {
626 // For the color of the additional info the inactive text color
627 // is not used as this might lead to unreadable text for some color schemes. Instead
628 // the text color is slightly mixed with the background color.
629 const QColor c1 = m_customTextColor ? *m_customTextColor : styleOption().palette.text().color();
630 const QColor c2 = styleOption().palette.background().color();
631 const int p1 = 70;
632 const int p2 = 100 - p1;
633 m_additionalInfoTextColor = QColor((c1.red() * p1 + c2.red() * p2) / 100,
634 (c1.green() * p1 + c2.green() * p2) / 100,
635 (c1.blue() * p1 + c2.blue() * p2) / 100);
636 }
637
638 QString KFileItemListWidget::roleText(TextId textId, const QVariant& roleValue) const
639 {
640 QString text;
641
642 switch (textId) {
643 case Name:
644 case Permissions:
645 case Owner:
646 case Group:
647 case Type:
648 case Destination:
649 case Path:
650 text = roleValue.toString();
651 break;
652
653 case Size: {
654 if (data().value("isDir").toBool()) {
655 // The item represents a directory. Show the number of sub directories
656 // instead of the file size of the directory.
657 if (!roleValue.isNull()) {
658 const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
659 text = i18ncp("@item:intable", "%1 item", "%1 items", size);
660 }
661 } else {
662 const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
663 text = KIO::convertSize(size);
664 }
665 break;
666 }
667
668 case Date: {
669 const QDateTime dateTime = roleValue.toDateTime();
670 text = KGlobal::locale()->formatDateTime(dateTime);
671 break;
672 }
673
674 default:
675 Q_ASSERT(false);
676 break;
677 }
678
679 return text;
680 }
681
682 void KFileItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap)
683 {
684 const bool isHiddenItem = m_text[Name].text().startsWith(QLatin1Char('.'));
685 qreal opacity;
686 if (isHiddenItem) {
687 opacity = painter->opacity();
688 painter->setOpacity(opacity * 0.3);
689 }
690
691 if (m_scaledPixmapSize != pixmap.size()) {
692 QPixmap scaledPixmap = pixmap;
693 KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize);
694 painter->drawPixmap(m_pixmapPos, scaledPixmap);
695
696 #ifdef KFILEITEMLISTWIDGET_DEBUG
697 painter->setPen(Qt::green);
698 painter->drawRect(QRectF(m_pixmapPos, QSizeF(scaledPixmap.size())));
699 #endif
700 } else {
701 painter->drawPixmap(m_pixmapPos, pixmap);
702 }
703
704 if (isHiddenItem) {
705 painter->setOpacity(opacity);
706 }
707 }
708
709 QPixmap KFileItemListWidget::pixmapForIcon(const QString& name, int size)
710 {
711 const KIcon icon(name);
712
713 int requestedSize;
714 if (size <= KIconLoader::SizeSmall) {
715 requestedSize = KIconLoader::SizeSmall;
716 } else if (size <= KIconLoader::SizeSmallMedium) {
717 requestedSize = KIconLoader::SizeSmallMedium;
718 } else if (size <= KIconLoader::SizeMedium) {
719 requestedSize = KIconLoader::SizeMedium;
720 } else if (size <= KIconLoader::SizeLarge) {
721 requestedSize = KIconLoader::SizeLarge;
722 } else if (size <= KIconLoader::SizeHuge) {
723 requestedSize = KIconLoader::SizeHuge;
724 } else if (size <= KIconLoader::SizeEnormous) {
725 requestedSize = KIconLoader::SizeEnormous;
726 } else if (size <= KIconLoader::SizeEnormous * 2) {
727 requestedSize = KIconLoader::SizeEnormous * 2;
728 } else {
729 requestedSize = size;
730 }
731
732 QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
733 if (requestedSize != size) {
734 KPixmapModifier::scale(pixmap, QSize(size, size));
735 }
736
737 return pixmap;
738 }
739
740 KFileItemListWidget::TextId KFileItemListWidget::roleTextId(const QByteArray& role)
741 {
742 static QHash<QByteArray, TextId> rolesHash;
743 if (rolesHash.isEmpty()) {
744 rolesHash.insert("name", Name);
745 rolesHash.insert("size", Size);
746 rolesHash.insert("date", Date);
747 rolesHash.insert("permissions", Permissions);
748 rolesHash.insert("owner", Owner);
749 rolesHash.insert("group", Group);
750 rolesHash.insert("type", Type);
751 rolesHash.insert("destination", Destination);
752 rolesHash.insert("path", Path);
753 }
754
755 return rolesHash.value(role);
756 }
757
758 #include "kfileitemlistwidget.moc"