Mercurial > hg > easyhg
view textabbrev.cpp @ 196:dbc8d97caaf4
* Avoid showing hard hyphen on Windows (I had thought this was in previous commit)
author | Chris Cannam |
---|---|
date | Fri, 24 Dec 2010 13:16:12 +0000 |
parents | f583e44d9d31 |
children | 8fd71f570884 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* EasyMercurial Based on HgExplorer by Jari Korhonen Copyright (c) 2010 Jari Korhonen Copyright (c) 2010 Chris Cannam Copyright (c) 2010 Queen Mary, University of London This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include "textabbrev.h" #include <QFontMetrics> #include <QApplication> #include <iostream> QString TextAbbrev::getDefaultEllipsis() { return "..."; } int TextAbbrev::getFuzzLength(QString ellipsis) { int len = ellipsis.length(); if (len < 3) return len + 3; else if (len > 5) return len + 5; else return len * 2; } int TextAbbrev::getFuzzWidth(const QFontMetrics &metrics, QString ellipsis) { int width = metrics.width(ellipsis); return width * 2; } QString TextAbbrev::abbreviateTo(QString text, int characters, Policy policy, QString ellipsis) { switch (policy) { case ElideEnd: case ElideEndAndCommonPrefixes: text = text.left(characters) + ellipsis; break; case ElideStart: text = ellipsis + text.right(characters); break; case ElideMiddle: if (characters > 2) { text = text.left(characters/2 + 1) + ellipsis + text.right(characters - (characters/2 + 1)); } else { text = text.left(characters) + ellipsis; } break; } return text; } QString TextAbbrev::abbreviate(QString text, int maxLength, Policy policy, bool fuzzy, QString ellipsis) { if (ellipsis == "") ellipsis = getDefaultEllipsis(); int fl = (fuzzy ? getFuzzLength(ellipsis) : 0); if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1; if (text.length() <= maxLength + fl) return text; int truncated = maxLength - ellipsis.length(); return abbreviateTo(text, truncated, policy, ellipsis); } QString TextAbbrev::abbreviate(QString text, const QFontMetrics &metrics, int &maxWidth, Policy policy, QString ellipsis, int wrapLines) { if (ellipsis == "") ellipsis = getDefaultEllipsis(); int tw = metrics.width(text); if (tw <= maxWidth) { maxWidth = tw; return text; } int truncated = text.length(); QString original = text; if (wrapLines < 2) { while (tw > maxWidth && truncated > 1) { truncated--; if (truncated > ellipsis.length()) { text = abbreviateTo(original, truncated, policy, ellipsis); } else { break; } tw = metrics.width(text); } maxWidth = tw; return text; } else { QStringList words = text.split(' ', QString::SkipEmptyParts); text = ""; tw = 0; int i = 0; QString good = ""; int lastUsed = 0; while (tw < maxWidth && i < words.size()) { if (text != "") text += " "; text += words[i++]; tw = metrics.width(text); if (tw < maxWidth) { good = text; lastUsed = i; } } if (tw < maxWidth) { maxWidth = tw; return text; } text = good; QString remainder; while (lastUsed < words.size()) { if (remainder != "") remainder += " "; remainder += words[lastUsed++]; } remainder = abbreviate(remainder, metrics, maxWidth, policy, ellipsis, wrapLines - 1); maxWidth = std::max(maxWidth, tw); text = text + '\n' + remainder; return text; } } QStringList TextAbbrev::abbreviate(const QStringList &texts, int maxLength, Policy policy, bool fuzzy, QString ellipsis) { if (policy == ElideEndAndCommonPrefixes && texts.size() > 1) { if (ellipsis == "") ellipsis = getDefaultEllipsis(); int fl = (fuzzy ? getFuzzLength(ellipsis) : 0); if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1; int maxOrigLength = 0; for (int i = 0; i < texts.size(); ++i) { int len = texts[i].length(); if (len > maxOrigLength) maxOrigLength = len; } if (maxOrigLength <= maxLength + fl) return texts; return abbreviate(elidePrefixes (texts, maxOrigLength - maxLength, ellipsis), maxLength, ElideEnd, fuzzy, ellipsis); } QStringList results; for (int i = 0; i < texts.size(); ++i) { results.push_back (abbreviate(texts[i], maxLength, policy, fuzzy, ellipsis)); } return results; } QStringList TextAbbrev::abbreviate(const QStringList &texts, const QFontMetrics &metrics, int &maxWidth, Policy policy, QString ellipsis) { if (policy == ElideEndAndCommonPrefixes && texts.size() > 1) { if (ellipsis == "") ellipsis = getDefaultEllipsis(); int maxOrigWidth = 0; for (int i = 0; i < texts.size(); ++i) { int w = metrics.width(texts[i]); if (w > maxOrigWidth) maxOrigWidth = w; } return abbreviate(elidePrefixes(texts, metrics, maxOrigWidth - maxWidth, ellipsis), metrics, maxWidth, ElideEnd, ellipsis); } QStringList results; int maxAbbrWidth = 0; for (int i = 0; i < texts.size(); ++i) { int width = maxWidth; QString abbr = abbreviate(texts[i], metrics, width, policy, ellipsis); if (width > maxAbbrWidth) maxAbbrWidth = width; results.push_back(abbr); } maxWidth = maxAbbrWidth; return results; } QStringList TextAbbrev::elidePrefixes(const QStringList &texts, int targetReduction, QString ellipsis) { if (texts.empty()) return texts; int plen = getPrefixLength(texts); int fl = getFuzzLength(ellipsis); if (plen < fl) return texts; QString prefix = texts[0].left(plen); int truncated = plen; if (plen >= targetReduction + fl) { truncated = plen - targetReduction; } else { truncated = fl; } prefix = abbreviate(prefix, truncated, ElideEnd, false, ellipsis); QStringList results; for (int i = 0; i < texts.size(); ++i) { results.push_back (prefix + texts[i].right(texts[i].length() - plen)); } return results; } QStringList TextAbbrev::elidePrefixes(const QStringList &texts, const QFontMetrics &metrics, int targetWidthReduction, QString ellipsis) { if (texts.empty()) return texts; int plen = getPrefixLength(texts); int fl = getFuzzLength(ellipsis); if (plen < fl) return texts; QString prefix = texts[0].left(plen); int pwid = metrics.width(prefix); int twid = pwid - targetWidthReduction; if (twid < metrics.width(ellipsis) * 2) twid = metrics.width(ellipsis) * 2; prefix = abbreviate(prefix, metrics, twid, ElideEnd, ellipsis); QStringList results; for (int i = 0; i < texts.size(); ++i) { results.push_back (prefix + texts[i].right(texts[i].length() - plen)); } return results; } static bool havePrefix(QString prefix, const QStringList &texts) { for (int i = 1; i < texts.size(); ++i) { if (!texts[i].startsWith(prefix)) return false; } return true; } int TextAbbrev::getPrefixLength(const QStringList &texts) { QString reference = texts[0]; if (reference == "" || havePrefix(reference, texts)) { return reference.length(); } int candidate = reference.length(); QString splitChars(";:,./#-!()$_+=[]{}\\"); while (--candidate > 1) { if (splitChars.contains(reference[candidate])) { if (havePrefix(reference.left(candidate), texts)) { break; } } } // std::cerr << "TextAbbrev::getPrefixLength: prefix length is " << candidate << std::endl; // for (int i = 0; i < texts.size(); ++i) { // std::cerr << texts[i].left(candidate).toStdString() << "|" << texts[i].right(texts[i].length() - candidate).toStdString() << std::endl; // } return candidate; }