00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "TextAbbrev.h"
00017
00018 #include <QFontMetrics>
00019 #include <QApplication>
00020
00021 #include <iostream>
00022
00023 QString
00024 TextAbbrev::getDefaultEllipsis()
00025 {
00026 return "...";
00027 }
00028
00029 int
00030 TextAbbrev::getFuzzLength(QString ellipsis)
00031 {
00032 int len = ellipsis.length();
00033 if (len < 3) return len + 3;
00034 else if (len > 5) return len + 5;
00035 else return len * 2;
00036 }
00037
00038 int
00039 TextAbbrev::getFuzzWidth(const QFontMetrics &metrics, QString ellipsis)
00040 {
00041 int width = metrics.width(ellipsis);
00042 return width * 2;
00043 }
00044
00045 QString
00046 TextAbbrev::abbreviateTo(QString text, int characters, Policy policy,
00047 QString ellipsis)
00048 {
00049 switch (policy) {
00050
00051 case ElideEnd:
00052 case ElideEndAndCommonPrefixes:
00053 text = text.left(characters) + ellipsis;
00054 break;
00055
00056 case ElideStart:
00057 text = ellipsis + text.right(characters);
00058 break;
00059
00060 case ElideMiddle:
00061 if (characters > 2) {
00062 text = text.left(characters/2 + 1) + ellipsis
00063 + text.right(characters - (characters/2 + 1));
00064 } else {
00065 text = text.left(characters) + ellipsis;
00066 }
00067 break;
00068 }
00069
00070 return text;
00071 }
00072
00073 QString
00074 TextAbbrev::abbreviate(QString text, int maxLength, Policy policy, bool fuzzy,
00075 QString ellipsis)
00076 {
00077 if (ellipsis == "") ellipsis = getDefaultEllipsis();
00078 int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
00079 if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
00080 if (text.length() <= maxLength + fl) return text;
00081
00082 int truncated = maxLength - ellipsis.length();
00083 return abbreviateTo(text, truncated, policy, ellipsis);
00084 }
00085
00086 QString
00087 TextAbbrev::abbreviate(QString text,
00088 const QFontMetrics &metrics, int &maxWidth,
00089 Policy policy, QString ellipsis)
00090 {
00091 if (ellipsis == "") ellipsis = getDefaultEllipsis();
00092
00093 int tw = metrics.width(text);
00094
00095 if (tw <= maxWidth) {
00096 maxWidth = tw;
00097 return text;
00098 }
00099
00100 int truncated = text.length();
00101 QString original = text;
00102
00103 while (tw > maxWidth && truncated > 1) {
00104
00105 truncated--;
00106
00107 if (truncated > ellipsis.length()) {
00108 text = abbreviateTo(original, truncated, policy, ellipsis);
00109 } else {
00110 break;
00111 }
00112
00113 tw = metrics.width(text);
00114 }
00115
00116 maxWidth = tw;
00117 return text;
00118 }
00119
00120 QStringList
00121 TextAbbrev::abbreviate(const QStringList &texts, int maxLength,
00122 Policy policy, bool fuzzy, QString ellipsis)
00123 {
00124 if (policy == ElideEndAndCommonPrefixes &&
00125 texts.size() > 1) {
00126
00127 if (ellipsis == "") ellipsis = getDefaultEllipsis();
00128 int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
00129 if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
00130
00131 int maxOrigLength = 0;
00132 for (int i = 0; i < texts.size(); ++i) {
00133 int len = texts[i].length();
00134 if (len > maxOrigLength) maxOrigLength = len;
00135 }
00136 if (maxOrigLength <= maxLength + fl) return texts;
00137
00138 return abbreviate(elidePrefixes
00139 (texts, maxOrigLength - maxLength, ellipsis),
00140 maxLength, ElideEnd, fuzzy, ellipsis);
00141 }
00142
00143 QStringList results;
00144 for (int i = 0; i < texts.size(); ++i) {
00145 results.push_back
00146 (abbreviate(texts[i], maxLength, policy, fuzzy, ellipsis));
00147 }
00148 return results;
00149 }
00150
00151 QStringList
00152 TextAbbrev::abbreviate(const QStringList &texts, const QFontMetrics &metrics,
00153 int &maxWidth, Policy policy, QString ellipsis)
00154 {
00155 if (policy == ElideEndAndCommonPrefixes &&
00156 texts.size() > 1) {
00157
00158 if (ellipsis == "") ellipsis = getDefaultEllipsis();
00159
00160 int maxOrigWidth = 0;
00161 for (int i = 0; i < texts.size(); ++i) {
00162 int w = metrics.width(texts[i]);
00163 if (w > maxOrigWidth) maxOrigWidth = w;
00164 }
00165
00166 return abbreviate(elidePrefixes(texts, metrics,
00167 maxOrigWidth - maxWidth, ellipsis),
00168 metrics, maxWidth, ElideEnd, ellipsis);
00169 }
00170
00171 QStringList results;
00172 int maxAbbrWidth = 0;
00173 for (int i = 0; i < texts.size(); ++i) {
00174 int width = maxWidth;
00175 QString abbr = abbreviate(texts[i], metrics, width, policy, ellipsis);
00176 if (width > maxAbbrWidth) maxAbbrWidth = width;
00177 results.push_back(abbr);
00178 }
00179 maxWidth = maxAbbrWidth;
00180 return results;
00181 }
00182
00183 QStringList
00184 TextAbbrev::elidePrefixes(const QStringList &texts,
00185 int targetReduction,
00186 QString ellipsis)
00187 {
00188 if (texts.empty()) return texts;
00189 int plen = getPrefixLength(texts);
00190 int fl = getFuzzLength(ellipsis);
00191 if (plen < fl) return texts;
00192
00193 QString prefix = texts[0].left(plen);
00194 int truncated = plen;
00195 if (plen >= targetReduction + fl) {
00196 truncated = plen - targetReduction;
00197 } else {
00198 truncated = fl;
00199 }
00200 prefix = abbreviate(prefix, truncated, ElideEnd, false, ellipsis);
00201
00202 QStringList results;
00203 for (int i = 0; i < texts.size(); ++i) {
00204 results.push_back
00205 (prefix + texts[i].right(texts[i].length() - plen));
00206 }
00207 return results;
00208 }
00209
00210 QStringList
00211 TextAbbrev::elidePrefixes(const QStringList &texts,
00212 const QFontMetrics &metrics,
00213 int targetWidthReduction,
00214 QString ellipsis)
00215 {
00216 if (texts.empty()) return texts;
00217 int plen = getPrefixLength(texts);
00218 int fl = getFuzzLength(ellipsis);
00219 if (plen < fl) return texts;
00220
00221 QString prefix = texts[0].left(plen);
00222 int pwid = metrics.width(prefix);
00223 int twid = pwid - targetWidthReduction;
00224 if (twid < metrics.width(ellipsis) * 2) twid = metrics.width(ellipsis) * 2;
00225 prefix = abbreviate(prefix, metrics, twid, ElideEnd, ellipsis);
00226
00227 QStringList results;
00228 for (int i = 0; i < texts.size(); ++i) {
00229 results.push_back
00230 (prefix + texts[i].right(texts[i].length() - plen));
00231 }
00232 return results;
00233 }
00234
00235 static bool
00236 havePrefix(QString prefix, const QStringList &texts)
00237 {
00238 for (int i = 1; i < texts.size(); ++i) {
00239 if (!texts[i].startsWith(prefix)) return false;
00240 }
00241 return true;
00242 }
00243
00244 int
00245 TextAbbrev::getPrefixLength(const QStringList &texts)
00246 {
00247 QString reference = texts[0];
00248
00249 if (reference == "" || havePrefix(reference, texts)) {
00250 return reference.length();
00251 }
00252
00253 int candidate = reference.length();
00254 QString splitChars(";:,./#-!()$_+=[]{}\\");
00255
00256 while (--candidate > 1) {
00257 if (splitChars.contains(reference[candidate])) {
00258 if (havePrefix(reference.left(candidate), texts)) {
00259 break;
00260 }
00261 }
00262 }
00263
00264
00265
00266
00267
00268
00269 return candidate;
00270 }
00271