svgui
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006-2007 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 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 // SVDEBUG << "TextAbbrev::getPrefixLength: prefix length is " << candidate << endl; 00265 // for (int i = 0; i < texts.size(); ++i) { 00266 // cerr << texts[i].left(candidate) << "|" << texts[i].right(texts[i].length() - candidate) << endl; 00267 // } 00268 00269 return candidate; 00270 } 00271