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