Index: src/filewidgets/kdiroperatordetailview.cpp =================================================================== --- src/filewidgets/kdiroperatordetailview.cpp +++ src/filewidgets/kdiroperatordetailview.cpp @@ -19,7 +19,6 @@ #include "kdiroperatordetailview_p.h" #include -#include #include #include @@ -85,25 +84,108 @@ bool KDirOperatorDetailView::event(QEvent *event) { - if (event->type() == QEvent::Polish) { - QHeaderView *headerView = header(); - headerView->setSectionResizeMode(0, QHeaderView::Stretch); - headerView->setSectionResizeMode(1, QHeaderView::ResizeToContents); - headerView->setSectionResizeMode(2, QHeaderView::ResizeToContents); - headerView->setStretchLastSection(false); - headerView->setSectionsMovable(false); - - setColumnHidden(KDirModel::Size, m_hideDetailColumns); - setColumnHidden(KDirModel::ModifiedTime, m_hideDetailColumns); - hideColumn(KDirModel::Type); - hideColumn(KDirModel::Permissions); - hideColumn(KDirModel::Owner); - hideColumn(KDirModel::Group); - } else if (event->type() == QEvent::UpdateRequest) { - // A wheel movement will scroll 4 items - if (model()->rowCount()) { - verticalScrollBar()->setSingleStep((sizeHintForRow(0) / 3) * 4); - } + QHeaderView *headerView = header(); + auto fnt = font(); + switch (auto type = event->type()) { + case QEvent::Resize: + case QEvent::Polish: + headerView->setSectionResizeMode(0, QHeaderView::Stretch); + headerView->setSectionResizeMode(1, QHeaderView::ResizeToContents); + headerView->setSectionResizeMode(2, QHeaderView::ResizeToContents); + headerView->setStretchLastSection(false); + headerView->setSectionsMovable(false); + + setColumnHidden(KDirModel::Size, m_hideDetailColumns); + setColumnHidden(KDirModel::ModifiedTime, m_hideDetailColumns); + hideColumn(KDirModel::Type); + hideColumn(KDirModel::Permissions); + hideColumn(KDirModel::Owner); + hideColumn(KDirModel::Group); + m_setInteractiveResizeMode = false; + fnt.setLetterSpacing(QFont::PercentageSpacing, 100); + setFont(fnt); + if (type == QEvent::Polish) { + // the polish event seems to arrive only once during our lifetime so + // this is a good moment for some JIT initialisation. + for (int i = 0 ; i < KDirModel::ColumnCount ; ++i) { + m_currentColumnWidth[i] = -1; + } + // install the section resize handler + connect(headerView, &QHeaderView::sectionResized, + [=](int column, int, int newSize) { + if (newSize > 0 && model()->rowCount() > 0) { + // store the new width; note that we may be called multiple times + // for columns in Stretch mode, with increasingly accurate sizes. + m_currentColumnWidth[column] = newSize; + // for some reason making a selective ResizeMode setting here + // has no effect; we need to set interactive mode on all sections + // at a later stage. Queue that now, and don't touch any + // section settings directly. + m_setInteractiveResizeMode = true; + } + }); + } + break; + case QEvent::UpdateRequest: + // A wheel movement will scroll 4 items + if (model()->rowCount()) { + verticalScrollBar()->setSingleStep((sizeHintForRow(0) / 3) * 4); + } + break; + case QEvent::Paint: + // event analysis confirms that the 1st paint event arrives after all headers have + // had a size set, so we can now set the definitive section size explicitly and + // activate interactive mode. The results is that section size is set once according + // to the principles defined above (Polish case) but can then be adapted by the user, + // for instance when navigating to a different directory. + if (m_setInteractiveResizeMode) { + headerView->setSectionResizeMode(QHeaderView::Interactive); + // define a minimum width for the name column, here a + // a third more than the width of the date column. + const int minNameWidth = headerView->sectionSize(2) * 1.33 + 0.5; + // compensation for very narrow views: impose a minimum name column width and + // reduce letterspacing by a small amount. NB: here we use sectionSize() to obtain + // current widths. + if (headerView->sectionSize(0) > 0 && headerView->sectionSize(0) < minNameWidth) { + m_currentColumnWidth[0] = minNameWidth; + const int fntSpacing = 90; + // determine how much space we will gain in the date column; its contents follow the + // same pattern with the same number of spaces in the entire column. + const auto mdl = model(); + const QString& content = mdl->data(mdl->index(0, 2)).toString(); + // regular width + const double dateWidthA = QFontMetrics(fnt).size(Qt::TextSingleLine, content).width(); + fnt.setLetterSpacing(QFont::PercentageSpacing, fntSpacing); + // gain = condensed width / regular width + double spaceGain = QFontMetrics(fnt).size(Qt::TextSingleLine, content).width() / dateWidthA; + // reduce the size and date columns by half as much + spaceGain = 0.5 + spaceGain / 2; + auto oldWidth = headerView->sectionSize(2); + m_currentColumnWidth[2] = oldWidth * spaceGain + 0.5; + const auto comp2 = oldWidth - m_currentColumnWidth[2]; + oldWidth = headerView->sectionSize(1); + m_currentColumnWidth[1] = oldWidth * spaceGain + 0.5; + const auto comp1 = oldWidth - m_currentColumnWidth[1]; + // the name column gets the intended size plus the space gained on the other columns + m_currentColumnWidth[0] += comp1 + comp2; + setFont(fnt); + } + // set the values we want to set explicitly + for (int i = 0 ; i < KDirModel::ColumnCount ; ++i) { + if (m_currentColumnWidth[i] > 0) { + // set the obtained width explicitly + headerView->resizeSection(i, m_currentColumnWidth[i]); + } + } + headerView->setSectionsMovable(true); + // we only do this once after receiving a Polish or Resize event, + // both of which reset the column size mode. + m_setInteractiveResizeMode = false; + } + break; + default: + // noop + break; } return QTreeView::event(event); Index: src/filewidgets/kdiroperatordetailview_p.h =================================================================== --- src/filewidgets/kdiroperatordetailview_p.h +++ src/filewidgets/kdiroperatordetailview_p.h @@ -22,6 +22,7 @@ #include #include +#include class QAbstractItemModel; @@ -50,6 +51,8 @@ private: bool m_hideDetailColumns; + bool m_setInteractiveResizeMode; + int m_currentColumnWidth[KDirModel::ColumnCount]; }; #endif