diff --git a/src/mode/katemodemenulist.h b/src/mode/katemodemenulist.h --- a/src/mode/katemodemenulist.h +++ b/src/mode/katemodemenulist.h @@ -287,6 +287,7 @@ const QIcon m_checkIcon = QIcon::fromTheme(QStringLiteral("checkbox")); QIcon m_emptyIcon; static const int m_iconSize = 16; + int m_defaultHeightItemSection; QPointer m_doc; diff --git a/src/mode/katemodemenulist.cpp b/src/mode/katemodemenulist.cpp --- a/src/mode/katemodemenulist.cpp +++ b/src/mode/katemodemenulist.cpp @@ -124,7 +124,7 @@ if (overlapScrollBar()) { QHBoxLayout *layoutScrollBar = new QHBoxLayout(); layoutScrollBar->addWidget(m_scroll); - layoutScrollBar->setContentsMargins(2, 2, 2, 2); + layoutScrollBar->setContentsMargins(1, 1, 1, 1); m_layoutList->addLayout(layoutScrollBar, 0, 0, Qt::AlignRight); } @@ -170,13 +170,12 @@ /* * The width of the text container in the item, in pixels. This is used to make * a custom word wrap and prevent the item's text from passing under the scroll bar. - * NOTE: 12 = the edges */ int maxWidthText; if (overlapScrollBar()) { - maxWidthText = m_list->sizeHint().width() - m_scroll->sizeHint().width() - m_iconSize - 12; + maxWidthText = m_list->sizeHint().width() - m_scroll->sizeHint().width() - m_iconSize - 10; } else { - maxWidthText = m_list->sizeHint().width() - m_list->verticalScrollBar()->sizeHint().width() - m_iconSize - 19; + maxWidthText = m_list->sizeHint().width() - m_list->verticalScrollBar()->sizeHint().width() - m_iconSize - 12; } // Transparent color used as background in the sections. @@ -189,6 +188,7 @@ * which will remain hidden and will only be shown when necessary. */ createSectionList(QString(), transparentBrush, false); + m_defaultHeightItemSection = m_list->visualRect(m_model->index(0, 0)).height(); m_list->setRowHidden(0, true); /* @@ -261,7 +261,7 @@ if (m_list->layoutDirection() == Qt::RightToLeft) { label->setAlignment(Qt::AlignRight); } - label->setTextFormat(Qt::RichText); + label->setTextFormat(Qt::PlainText); label->setIndent(6); /* @@ -282,6 +282,25 @@ m_list->setIndexWidget(m_model->index(section->row(), 0), label); m_list->selectionModel()->select(section->index(), QItemSelectionModel::Deselect); + // Apply word wrap in sections, for long labels. + int containerTextWidth; + if (overlapScrollBar()) { + containerTextWidth = m_list->sizeHint().width() - m_scroll->sizeHint().width() - 2; + } else { + containerTextWidth = m_list->sizeHint().width() - m_list->verticalScrollBar()->sizeHint().width() - 2; + } + int heightSectionMargin = m_list->visualRect(m_model->index(section->row(), 0)).height() - label->sizeHint().height(); + + if (label->sizeHint().width() > containerTextWidth) { + label->setText(setWordWrap(label->text(), containerTextWidth - label->indent(), label->fontMetrics())); + if (heightSectionMargin < 2) { + heightSectionMargin = 2; + } + section->setSizeHint(QSize(section->sizeHint().width(), label->sizeHint().height() + heightSectionMargin)); + } else if (heightSectionMargin < 2) { + section->setSizeHint(QSize(section->sizeHint().width(), label->sizeHint().height() + heightSectionMargin)); + } + return section; } @@ -493,7 +512,7 @@ QString KateModeMenuList::setWordWrap(const QString &text, const int maxWidth, const QFontMetrics &fontMetrics) const { // Get the length of the text, in pixels, and compare it with the container - if (fontMetrics.boundingRect(text).width() <= maxWidth) { + if (fontMetrics.horizontalAdvance(text) <= maxWidth) { return text; } @@ -506,37 +525,58 @@ QString tmpLineText = QString(); for (int i = 0; i < words.count() - 1; ++i) { - tmpLineText += words[i]; + // Elide mode in long words + if (fontMetrics.horizontalAdvance(words[i]) > maxWidth) { + if (!tmpLineText.isEmpty()) { + newText += tmpLineText + QLatin1Char('\n'); + tmpLineText.clear(); + } + newText += fontMetrics.elidedText(words[i], m_list->layoutDirection() == Qt::RightToLeft ? Qt::ElideLeft : Qt::ElideRight, maxWidth) + QLatin1Char('\n'); + continue; + } else { + tmpLineText += words[i]; + } // This prevents the last line of text from having only one word with 1 or 2 chars - if (i == words.count() - 3 && words[i + 2].length() <= 2 && fontMetrics.boundingRect(tmpLineText + QLatin1Char(' ') + words[i + 1] + QLatin1Char(' ') + words[i + 2]).width() > maxWidth) { + if (i == words.count() - 3 && words[i + 2].length() <= 2 && fontMetrics.horizontalAdvance(tmpLineText + QLatin1Char(' ') + words[i + 1] + QLatin1Char(' ') + words[i + 2]) > maxWidth) { newText += tmpLineText + QLatin1Char('\n'); tmpLineText.clear(); } // Add line break if the maxWidth is exceeded with the next word - else if (fontMetrics.boundingRect(tmpLineText + QLatin1Char(' ') + words[i + 1]).width() > maxWidth) { + else if (fontMetrics.horizontalAdvance(tmpLineText + QLatin1Char(' ') + words[i + 1]) > maxWidth) { newText += tmpLineText + QLatin1Char('\n'); tmpLineText.clear(); } else { tmpLineText.append(QLatin1Char(' ')); } } // Add line breaks in delimiters, if the last word is greater than the container - if (fontMetrics.boundingRect(words[words.count() - 1]).width() > maxWidth) { + bool bElidedLastWord = false; + if (fontMetrics.horizontalAdvance(words[words.count() - 1]) > maxWidth) { + bElidedLastWord = true; const int lastw = words.count() - 1; for (int c = words[lastw].length() - 1; c >= 0; --c) { - if (isDelimiter(words[lastw][c].unicode()) && fontMetrics.boundingRect(words[lastw].mid(0, c + 1)).width() <= maxWidth) { - words[lastw].insert(c + 1, QLatin1Char('\n')); + if (isDelimiter(words[lastw][c].unicode()) && fontMetrics.horizontalAdvance(words[lastw].mid(0, c + 1)) <= maxWidth) { + bElidedLastWord = false; + if (fontMetrics.horizontalAdvance(words[lastw].mid(c + 1)) > maxWidth) { + words[lastw] = words[lastw].mid(0, c + 1) + QLatin1Char('\n') + fontMetrics.elidedText(words[lastw].mid(c + 1), m_list->layoutDirection() == Qt::RightToLeft ? Qt::ElideLeft : Qt::ElideRight, maxWidth); + } else { + words[lastw].insert(c + 1, QLatin1Char('\n')); + } break; } } } if (!tmpLineText.isEmpty()) { newText += tmpLineText; } - newText += words[words.count() - 1]; + if (bElidedLastWord) { + newText += fontMetrics.elidedText(words[words.count() - 1], m_list->layoutDirection() == Qt::RightToLeft ? Qt::ElideLeft : Qt::ElideRight, maxWidth); + } else { + newText += words[words.count() - 1]; + } return newText; } @@ -930,22 +970,43 @@ if (m_bestResults.isEmpty()) { listView->setRowHidden(0, true); if (firstSection > 0) { - m_parentMenu->m_list->setRowHidden(firstSection - 1, true); + listView->setRowHidden(firstSection - 1, true); } - } - // Show "Best Search Matches" section, if there are items. - else { - // Show title in singular or plural, depending on the number of items - QLabel *labelSection = static_cast(listView->indexWidget(m_parentMenu->m_model->index(0, 0))); + } else { + /* + * Show "Best Search Matches" section, if there are items. + */ + + // Show title in singular or plural, depending on the number of items. + QLabel *labelSection = static_cast(listView->indexWidget(listModel->index(0, 0))); if (m_bestResults.size() == 1) { - labelSection->setText( - i18nc("Title (in singular) of the best result in an item search. Please, that the translation doesn't have more than 34 characters, since the menu where it's displayed is small and fixed.", "Best Search Match")); + labelSection->setText(i18nc("Title (in singular) of the best result in an item search. Please, that the translation doesn't have more than 34 characters, since the menu where it's displayed is small and fixed.", "Best Search Match")); } else { - labelSection->setText( - i18nc("Title (in plural) of the best results in an item search. Please, that the translation doesn't have more than 34 characters, since the menu where it's displayed is small and fixed.", "Best Search Matches")); + labelSection->setText(i18nc("Title (in plural) of the best results in an item search. Please, that the translation doesn't have more than 34 characters, since the menu where it's displayed is small and fixed.", "Best Search Matches")); } - listView->setRowHidden(0, false); + int heightSectionMargin = m_parentMenu->m_defaultHeightItemSection - labelSection->sizeHint().height(); + if (heightSectionMargin < 2) { + heightSectionMargin = 2; + } + const int listWidth = listView->sizeHint().width() - 1; + int maxWidthText; + if (overlapScrollBar()) { + maxWidthText = listWidth - m_parentMenu->m_scroll->sizeHint().width() + 5; + } else { + maxWidthText = listWidth - listView->verticalScrollBar()->sizeHint().width(); + } + // NOTE: labelSection->sizeHint().width() == labelSection->indent() + labelSection->fontMetrics().horizontalAdvance(labelSection->text()) + const bool bSectionMultiline = labelSection->sizeHint().width() > maxWidthText; + maxWidthText -= labelSection->indent(); + if (!bSectionMultiline) { + listModel->item(0, 0)->setSizeHint(QSize(listModel->item(0, 0)->sizeHint().width(), labelSection->sizeHint().height() + heightSectionMargin)); + listView->setRowHidden(0, false); + } + + /* + * Show items in "Best Search Matches" section. + */ int rowModelBestResults = 0; // New position in the model // Special Case: always show the "R Script" mode first by typing "r" in the search box @@ -973,6 +1034,15 @@ lastItem = rowModelBestResults; } + // Add word wrap in long section titles. + if (bSectionMultiline) { + if (listView->visualRect(listModel->index(lastItem, 0)).bottom() + labelSection->sizeHint().height() + heightSectionMargin > listView->geometry().height() || labelSection->sizeHint().width() > listWidth) { + labelSection->setText(m_parentMenu->setWordWrap(labelSection->text(), maxWidthText, labelSection->fontMetrics())); + } + listModel->item(0, 0)->setSizeHint(QSize(listModel->item(0, 0)->sizeHint().width(), labelSection->sizeHint().height() + heightSectionMargin)); + listView->setRowHidden(0, false); + } + m_parentMenu->m_list->setCurrentItem(1); }