From 60b868108151463a702e8c10933b0ceb99f11bbe Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Sat, 14 Apr 2012 00:22:08 +0200 Subject: [PATCH] Allow to optionally limit the maximum number of text lines Showing the whole filename unclipped seems to be a good default, however for users with a lot of files that have extremely long names this might get a problem especially in the icons-view. - Allow to limit the maximum number of lines in the icons-view - Allow to specify a maximum width in the compact-view (No limit is required for the details-view, as the name is shortened automatically to show other columns) BUG: 288596 FIXED-IN: 4.9.0 --- src/kitemviews/kfileitemlistwidget.cpp | 47 +++++++++++--- src/kitemviews/kitemliststyleoption.cpp | 6 +- src/kitemviews/kitemliststyleoption.h | 1 + src/kitemviews/kitemlistview.cpp | 27 +++++--- src/settings/dolphin_compactmodesettings.kcfg | 4 ++ src/settings/dolphin_iconsmodesettings.kcfg | 4 ++ src/settings/viewmodes/viewsettingstab.cpp | 62 +++++++++++++++---- src/settings/viewmodes/viewsettingstab.h | 3 +- src/views/dolphinitemlistcontainer.cpp | 24 ++++++- 9 files changed, 140 insertions(+), 38 deletions(-) diff --git a/src/kitemviews/kfileitemlistwidget.cpp b/src/kitemviews/kfileitemlistwidget.cpp index f3b4da892..5c5690c40 100644 --- a/src/kitemviews/kfileitemlistwidget.cpp +++ b/src/kitemviews/kfileitemlistwidget.cpp @@ -279,7 +279,8 @@ QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view) case IconsLayout: { const QString text = KStringHandler::preProcessWrap(values["name"].toString()); - const qreal maxWidth = view->itemSize().width() - 2 * option.padding; + const qreal itemWidth = view->itemSize().width(); + const qreal maxWidth = itemWidth - 2 * option.padding; QTextLine line; // Calculate the number of lines required for wrapping the name @@ -298,11 +299,14 @@ QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view) layout.endLayout(); // Add one line for each additional information - const qreal height = textHeight + - additionalRolesCount * option.fontMetrics.lineSpacing() + - option.iconSize + - option.padding * 3; - return QSizeF(view->itemSize().width(), height); + textHeight += additionalRolesCount * option.fontMetrics.lineSpacing(); + + const qreal maxTextHeight = option.maxTextSize.height(); + if (maxTextHeight > 0 && textHeight > maxTextHeight) { + textHeight = maxTextHeight; + } + + return QSizeF(itemWidth, textHeight + option.iconSize + option.padding * 3); } case CompactLayout: { @@ -316,7 +320,11 @@ QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view) maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth); } - const qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth; + qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth; + const qreal maxWidth = option.maxTextSize.width(); + if (maxWidth > 0 && width > maxWidth) { + width = maxWidth; + } const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing()); return QSizeF(width, height); } @@ -756,25 +764,46 @@ void KFileItemListWidget::updateIconsLayoutTextCache() // Initialize properties for the "name" role. It will be used as anchor // for initializing the position of the other roles. TextInfo* nameTextInfo = m_textInfo.value("name"); - nameTextInfo->staticText.setText(KStringHandler::preProcessWrap(values["name"].toString())); + const QString nameText = KStringHandler::preProcessWrap(values["name"].toString()); + nameTextInfo->staticText.setText(nameText); // Calculate the number of lines required for the name and the required width qreal nameWidth = 0; qreal nameHeight = 0; QTextLine line; + const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0); + const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount; + QTextLayout layout(nameTextInfo->staticText.text(), option.font); layout.setTextOption(nameTextInfo->staticText.textOption()); layout.beginLayout(); + int nameLineIndex = 0; while ((line = layout.createLine()).isValid()) { line.setLineWidth(maxWidth); nameWidth = qMax(nameWidth, line.naturalTextWidth()); nameHeight += line.height(); + + ++nameLineIndex; + if (nameLineIndex == maxNameLines) { + // The maximum number of textlines has been reached. If this is + // the case provide an elided text if necessary. + const int textLength = line.textStart() + line.textLength(); + if (textLength < nameText.length()) { + // Elide the last line of the text + QString lastTextLine = nameText.mid(line.textStart(), line.textLength()); + lastTextLine = option.fontMetrics.elidedText(lastTextLine, + Qt::ElideRight, + line.naturalTextWidth() - 1); + const QString elidedText = nameText.left(line.textStart()) + lastTextLine; + nameTextInfo->staticText.setText(elidedText); + } + break; + } } layout.endLayout(); // Use one line for each additional information - const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0); nameTextInfo->staticText.setTextWidth(maxWidth); nameTextInfo->pos = QPointF(padding, widgetHeight - nameHeight - diff --git a/src/kitemviews/kitemliststyleoption.cpp b/src/kitemviews/kitemliststyleoption.cpp index c512fa43e..36cfeb088 100644 --- a/src/kitemviews/kitemliststyleoption.cpp +++ b/src/kitemviews/kitemliststyleoption.cpp @@ -30,7 +30,8 @@ KItemListStyleOption::KItemListStyleOption() : horizontalMargin(0), verticalMargin(0), iconSize(KIconLoader::SizeMedium), - extendedSelectionRegion(false) + extendedSelectionRegion(false), + maxTextSize() { } @@ -43,7 +44,8 @@ KItemListStyleOption::KItemListStyleOption(const KItemListStyleOption& other) : horizontalMargin(other.horizontalMargin), verticalMargin(other.verticalMargin), iconSize(other.iconSize), - extendedSelectionRegion(other.extendedSelectionRegion) + extendedSelectionRegion(other.extendedSelectionRegion), + maxTextSize(other.maxTextSize) { } diff --git a/src/kitemviews/kitemliststyleoption.h b/src/kitemviews/kitemliststyleoption.h index 62441ef4b..1a304fc28 100644 --- a/src/kitemviews/kitemliststyleoption.h +++ b/src/kitemviews/kitemliststyleoption.h @@ -43,6 +43,7 @@ public: int verticalMargin; int iconSize; bool extendedSelectionRegion; + QSize maxTextSize; }; #endif diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 732ed24e4..c62523410 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -148,10 +148,10 @@ Qt::Orientation KItemListView::scrollOrientation() const return m_layouter->scrollOrientation(); } -void KItemListView::setItemSize(const QSizeF& itemSize) +void KItemListView::setItemSize(const QSizeF& size) { const QSizeF previousSize = m_itemSize; - if (itemSize == previousSize) { + if (size == previousSize) { return; } @@ -159,14 +159,14 @@ void KItemListView::setItemSize(const QSizeF& itemSize) // are changed in the grid layout. Although the animation // engine can handle this usecase, it looks obtrusive. const bool animate = !changesItemGridLayout(m_layouter->size(), - itemSize, + size, m_layouter->itemMargin()); const bool alternateBackgroundsChanged = (m_visibleRoles.count() > 1) && - (( m_itemSize.isEmpty() && !itemSize.isEmpty()) || - (!m_itemSize.isEmpty() && itemSize.isEmpty())); + (( m_itemSize.isEmpty() && !size.isEmpty()) || + (!m_itemSize.isEmpty() && size.isEmpty())); - m_itemSize = itemSize; + m_itemSize = size; if (alternateBackgroundsChanged) { // For an empty item size alternate backgrounds are drawn if more than @@ -175,23 +175,23 @@ void KItemListView::setItemSize(const QSizeF& itemSize) updateAlternateBackgrounds(); } - if (itemSize.isEmpty()) { + if (size.isEmpty()) { if (m_headerWidget->automaticColumnResizing()) { updatePreferredColumnWidths(); } else { // Only apply the changed height and respect the header widths // set by the user const qreal currentWidth = m_layouter->itemSize().width(); - const QSizeF newSize(currentWidth, itemSize.height()); + const QSizeF newSize(currentWidth, size.height()); m_layouter->setItemSize(newSize); } } else { - m_layouter->setItemSize(itemSize); + m_layouter->setItemSize(size); } m_sizeHintResolver->clearCache(); doLayout(animate ? Animation : NoAnimation); - onItemSizeChanged(itemSize, previousSize); + onItemSizeChanged(size, previousSize); } QSizeF KItemListView::itemSize() const @@ -392,6 +392,12 @@ void KItemListView::setStyleOption(const KItemListStyleOption& option) updateGroupHeaderHeight(); } + if (animate && previousOption.maxTextSize != option.maxTextSize) { + // Animating a change of the maximum text size just results in expensive + // temporary eliding and clipping operations and does not look good visually. + animate = false; + } + QHashIterator it(m_visibleItems); while (it.hasNext()) { it.next(); @@ -399,6 +405,7 @@ void KItemListView::setStyleOption(const KItemListStyleOption& option) } m_sizeHintResolver->clearCache(); + m_layouter->markAsDirty(); doLayout(animate ? Animation : NoAnimation); onStyleOptionChanged(option, previousOption); diff --git a/src/settings/dolphin_compactmodesettings.kcfg b/src/settings/dolphin_compactmodesettings.kcfg index 40b9dfa32..b9000c8e2 100644 --- a/src/settings/dolphin_compactmodesettings.kcfg +++ b/src/settings/dolphin_compactmodesettings.kcfg @@ -36,5 +36,9 @@ KIconLoader::SizeLarge + + + 0 + diff --git a/src/settings/dolphin_iconsmodesettings.kcfg b/src/settings/dolphin_iconsmodesettings.kcfg index fb01a8c65..52cd9a28c 100644 --- a/src/settings/dolphin_iconsmodesettings.kcfg +++ b/src/settings/dolphin_iconsmodesettings.kcfg @@ -40,5 +40,9 @@ 1 + + + 0 + diff --git a/src/settings/viewmodes/viewsettingstab.cpp b/src/settings/viewmodes/viewsettingstab.cpp index 23b2999b1..fe043a788 100644 --- a/src/settings/viewmodes/viewsettingstab.cpp +++ b/src/settings/viewmodes/viewsettingstab.cpp @@ -41,7 +41,8 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) : m_defaultSizeSlider(0), m_previewSizeSlider(0), m_fontRequester(0), - m_textWidthBox(0), + m_widthBox(0), + m_maxLinesBox(0), m_expandableFolders(0) { QVBoxLayout* topLayout = new QVBoxLayout(this); @@ -83,15 +84,38 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) : switch (m_mode) { case IconsMode: { - QLabel* textWidthLabel = new QLabel(i18nc("@label:listbox", "Text width:"), textGroup); - m_textWidthBox = new KComboBox(textGroup); - m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Small")); - m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Medium")); - m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Large")); - m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Huge")); - - textGroupLayout->addWidget(textWidthLabel, 2, 0, Qt::AlignRight); - textGroupLayout->addWidget(m_textWidthBox, 2, 1); + QLabel* widthLabel = new QLabel(i18nc("@label:listbox", "Width:"), textGroup); + m_widthBox = new KComboBox(textGroup); + m_widthBox->addItem(i18nc("@item:inlistbox Text width", "Small")); + m_widthBox->addItem(i18nc("@item:inlistbox Text width", "Medium")); + m_widthBox->addItem(i18nc("@item:inlistbox Text width", "Large")); + m_widthBox->addItem(i18nc("@item:inlistbox Text width", "Huge")); + + QLabel* maxLinesLabel = new QLabel(i18nc("@label:listbox", "Maximum lines:"), textGroup); + m_maxLinesBox = new KComboBox(textGroup); + m_maxLinesBox->addItem(i18nc("@item:inlistbox Maximum lines", "Unlimited")); + m_maxLinesBox->addItem(i18nc("@item:inlistbox Maximum lines", "1")); + m_maxLinesBox->addItem(i18nc("@item:inlistbox Maximum lines", "2")); + m_maxLinesBox->addItem(i18nc("@item:inlistbox Maximum lines", "3")); + m_maxLinesBox->addItem(i18nc("@item:inlistbox Maximum lines", "4")); + m_maxLinesBox->addItem(i18nc("@item:inlistbox Maximum lines", "5")); + + textGroupLayout->addWidget(widthLabel, 2, 0, Qt::AlignRight); + textGroupLayout->addWidget(m_widthBox, 2, 1); + textGroupLayout->addWidget(maxLinesLabel, 3, 0, Qt::AlignRight); + textGroupLayout->addWidget(m_maxLinesBox, 3, 1); + break; + } + case CompactMode: { + QLabel* maxWidthLabel = new QLabel(i18nc("@label:listbox", "Maximum width:"), textGroup); + m_widthBox = new KComboBox(textGroup); + m_widthBox->addItem(i18nc("@item:inlistbox Maximum width", "Unlimited")); + m_widthBox->addItem(i18nc("@item:inlistbox Maximum width", "Small")); + m_widthBox->addItem(i18nc("@item:inlistbox Maximum width", "Medium")); + m_widthBox->addItem(i18nc("@item:inlistbox Maximum width", "Large")); + + textGroupLayout->addWidget(maxWidthLabel, 2, 0, Qt::AlignRight); + textGroupLayout->addWidget(m_widthBox, 2, 1); break; } case DetailsMode: @@ -114,7 +138,11 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) : switch (m_mode) { case IconsMode: - connect(m_textWidthBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed())); + connect(m_widthBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed())); + connect(m_maxLinesBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed())); + break; + case CompactMode: + connect(m_widthBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed())); break; case DetailsMode: connect(m_expandableFolders, SIGNAL(toggled(bool)), this, SIGNAL(changed())); @@ -135,7 +163,11 @@ void ViewSettingsTab::applySettings() switch (m_mode) { case IconsMode: - IconsModeSettings::setTextWidthIndex(m_textWidthBox->currentIndex()); + IconsModeSettings::setTextWidthIndex(m_widthBox->currentIndex()); + IconsModeSettings::setMaximumTextLines(m_maxLinesBox->currentIndex()); + break; + case CompactMode: + CompactModeSettings::setMaximumTextWidthIndex(m_widthBox->currentIndex()); break; case DetailsMode: DetailsModeSettings::setExpandableFolders(m_expandableFolders->isChecked()); @@ -179,7 +211,11 @@ void ViewSettingsTab::loadSettings() { switch (m_mode) { case IconsMode: - m_textWidthBox->setCurrentIndex(IconsModeSettings::textWidthIndex()); + m_widthBox->setCurrentIndex(IconsModeSettings::textWidthIndex()); + m_maxLinesBox->setCurrentIndex(IconsModeSettings::maximumTextLines()); + break; + case CompactMode: + m_widthBox->setCurrentIndex(CompactModeSettings::maximumTextWidthIndex()); break; case DetailsMode: m_expandableFolders->setChecked(DetailsModeSettings::expandableFolders()); diff --git a/src/settings/viewmodes/viewsettingstab.h b/src/settings/viewmodes/viewsettingstab.h index b21fc102c..2115da1bc 100644 --- a/src/settings/viewmodes/viewsettingstab.h +++ b/src/settings/viewmodes/viewsettingstab.h @@ -63,7 +63,8 @@ private: QSlider* m_previewSizeSlider; DolphinFontRequester* m_fontRequester; - KComboBox* m_textWidthBox; + KComboBox* m_widthBox; + KComboBox* m_maxLinesBox; QCheckBox* m_expandableFolders; }; diff --git a/src/views/dolphinitemlistcontainer.cpp b/src/views/dolphinitemlistcontainer.cpp index e8c373492..88e10d8a3 100644 --- a/src/views/dolphinitemlistcontainer.cpp +++ b/src/views/dolphinitemlistcontainer.cpp @@ -222,6 +222,8 @@ void DolphinItemListContainer::updateGridSize() // Calculate the item-width and item-height int itemWidth; int itemHeight; + QSize maxTextSize; + switch (itemLayout()) { case KFileItemListView::IconsLayout: { const int minItemWidth = 48; @@ -238,7 +240,15 @@ void DolphinItemListContainer::updateGridSize() if (itemWidth < iconSize + padding * 2) { itemWidth = iconSize + padding * 2; } - itemHeight = padding * 3 + iconSize + styleOption.fontMetrics.height(); + + itemHeight = padding * 3 + iconSize + styleOption.fontMetrics.lineSpacing(); + if (IconsModeSettings::maximumTextLines() > 0) { + // A restriction is given for the maximum number of textlines (0 means + // having no restriction) + const int additionalInfoCount = m_fileItemListView->visibleRoles().count() - 1; + const int maxAdditionalLines = additionalInfoCount + IconsModeSettings::maximumTextLines(); + maxTextSize.rheight() = styleOption.fontMetrics.lineSpacing() * maxAdditionalLines; + } horizontalMargin = 4; verticalMargin = 8; @@ -247,14 +257,21 @@ void DolphinItemListContainer::updateGridSize() case KFileItemListView::CompactLayout: { itemWidth = padding * 4 + iconSize + styleOption.fontMetrics.height() * 5; const int textLinesCount = m_fileItemListView->visibleRoles().count(); - itemHeight = padding * 2 + qMax(iconSize, textLinesCount * styleOption.fontMetrics.height()); + itemHeight = padding * 2 + qMax(iconSize, textLinesCount * styleOption.fontMetrics.lineSpacing()); + + if (CompactModeSettings::maximumTextWidthIndex() > 0) { + // A restriction is given for the maximum width of the text (0 means + // having no restriction) + maxTextSize.rwidth() = styleOption.fontMetrics.height() * 10 * + CompactModeSettings::maximumTextWidthIndex(); + } horizontalMargin = 8; break; } case KFileItemListView::DetailsLayout: { itemWidth = -1; - itemHeight = padding * 2 + qMax(iconSize, styleOption.fontMetrics.height()); + itemHeight = padding * 2 + qMax(iconSize, styleOption.fontMetrics.lineSpacing()); break; } default: @@ -269,6 +286,7 @@ void DolphinItemListContainer::updateGridSize() styleOption.horizontalMargin = horizontalMargin; styleOption.verticalMargin = verticalMargin; styleOption.iconSize = iconSize; + styleOption.maxTextSize = maxTextSize; m_fileItemListView->beginTransaction(); m_fileItemListView->setStyleOption(styleOption); m_fileItemListView->setItemSize(QSizeF(itemWidth, itemHeight)); -- 2.47.3