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