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