comparison widgets/TextAbbrev.cpp @ 376:e1a9e478b7f2

* juggle some files around in order to free audioio, base, and system libraries from dependency on QtGui
author Chris Cannam
date Wed, 12 Mar 2008 17:42:56 +0000
parents
children 1fe7951a61e8
comparison
equal deleted inserted replaced
375:daaf1c435d98 376:e1a9e478b7f2
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2006-2007 Chris Cannam and QMUL.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #include "TextAbbrev.h"
17
18 #include <QFontMetrics>
19 #include <QApplication>
20
21 #include <iostream>
22
23 QString
24 TextAbbrev::getDefaultEllipsis()
25 {
26 return "...";
27 }
28
29 int
30 TextAbbrev::getFuzzLength(QString ellipsis)
31 {
32 int len = ellipsis.length();
33 if (len < 3) return len + 3;
34 else if (len > 5) return len + 5;
35 else return len * 2;
36 }
37
38 int
39 TextAbbrev::getFuzzWidth(const QFontMetrics &metrics, QString ellipsis)
40 {
41 int width = metrics.width(ellipsis);
42 return width * 2;
43 }
44
45 QString
46 TextAbbrev::abbreviateTo(QString text, int characters, Policy policy,
47 QString ellipsis)
48 {
49 switch (policy) {
50
51 case ElideEnd:
52 case ElideEndAndCommonPrefixes:
53 text = text.left(characters) + ellipsis;
54 break;
55
56 case ElideStart:
57 text = ellipsis + text.right(characters);
58 break;
59
60 case ElideMiddle:
61 if (characters > 2) {
62 text = text.left(characters/2 + 1) + ellipsis
63 + text.right(characters - (characters/2 + 1));
64 } else {
65 text = text.left(characters) + ellipsis;
66 }
67 break;
68 }
69
70 return text;
71 }
72
73 QString
74 TextAbbrev::abbreviate(QString text, int maxLength, Policy policy, bool fuzzy,
75 QString ellipsis)
76 {
77 if (ellipsis == "") ellipsis = getDefaultEllipsis();
78 int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
79 if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
80 if (text.length() <= maxLength + fl) return text;
81
82 int truncated = maxLength - ellipsis.length();
83 return abbreviateTo(text, truncated, policy, ellipsis);
84 }
85
86 QString
87 TextAbbrev::abbreviate(QString text,
88 const QFontMetrics &metrics, int &maxWidth,
89 Policy policy, QString ellipsis)
90 {
91 if (ellipsis == "") ellipsis = getDefaultEllipsis();
92
93 int tw = metrics.width(text);
94
95 if (tw <= maxWidth) {
96 maxWidth = tw;
97 return text;
98 }
99
100 int truncated = text.length();
101 QString original = text;
102
103 while (tw > maxWidth && truncated > 1) {
104
105 truncated--;
106
107 if (truncated > ellipsis.length()) {
108 text = abbreviateTo(original, truncated, policy, ellipsis);
109 } else {
110 break;
111 }
112
113 tw = metrics.width(text);
114 }
115
116 maxWidth = tw;
117 return text;
118 }
119
120 QStringList
121 TextAbbrev::abbreviate(const QStringList &texts, int maxLength,
122 Policy policy, bool fuzzy, QString ellipsis)
123 {
124 if (policy == ElideEndAndCommonPrefixes &&
125 texts.size() > 1) {
126
127 if (ellipsis == "") ellipsis = getDefaultEllipsis();
128 int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
129 if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
130
131 int maxOrigLength = 0;
132 for (int i = 0; i < texts.size(); ++i) {
133 int len = texts[i].length();
134 if (len > maxOrigLength) maxOrigLength = len;
135 }
136 if (maxOrigLength <= maxLength + fl) return texts;
137
138 return abbreviate(elidePrefixes
139 (texts, maxOrigLength - maxLength, ellipsis),
140 maxLength, ElideEnd, fuzzy, ellipsis);
141 }
142
143 QStringList results;
144 for (int i = 0; i < texts.size(); ++i) {
145 results.push_back
146 (abbreviate(texts[i], maxLength, policy, fuzzy, ellipsis));
147 }
148 return results;
149 }
150
151 QStringList
152 TextAbbrev::abbreviate(const QStringList &texts, const QFontMetrics &metrics,
153 int &maxWidth, Policy policy, QString ellipsis)
154 {
155 if (policy == ElideEndAndCommonPrefixes &&
156 texts.size() > 1) {
157
158 if (ellipsis == "") ellipsis = getDefaultEllipsis();
159
160 int maxOrigWidth = 0;
161 for (int i = 0; i < texts.size(); ++i) {
162 int w = metrics.width(texts[i]);
163 if (w > maxOrigWidth) maxOrigWidth = w;
164 }
165
166 return abbreviate(elidePrefixes(texts, metrics,
167 maxOrigWidth - maxWidth, ellipsis),
168 metrics, maxWidth, ElideEnd, ellipsis);
169 }
170
171 QStringList results;
172 int maxAbbrWidth = 0;
173 for (int i = 0; i < texts.size(); ++i) {
174 int width = maxWidth;
175 QString abbr = abbreviate(texts[i], metrics, width, policy, ellipsis);
176 if (width > maxAbbrWidth) maxAbbrWidth = width;
177 results.push_back(abbr);
178 }
179 maxWidth = maxAbbrWidth;
180 return results;
181 }
182
183 QStringList
184 TextAbbrev::elidePrefixes(const QStringList &texts,
185 int targetReduction,
186 QString ellipsis)
187 {
188 if (texts.empty()) return texts;
189 int plen = getPrefixLength(texts);
190 int fl = getFuzzLength(ellipsis);
191 if (plen < fl) return texts;
192
193 QString prefix = texts[0].left(plen);
194 int truncated = plen;
195 if (plen >= targetReduction + fl) {
196 truncated = plen - targetReduction;
197 } else {
198 truncated = fl;
199 }
200 prefix = abbreviate(prefix, truncated, ElideEnd, false, ellipsis);
201
202 QStringList results;
203 for (int i = 0; i < texts.size(); ++i) {
204 results.push_back
205 (prefix + texts[i].right(texts[i].length() - plen));
206 }
207 return results;
208 }
209
210 QStringList
211 TextAbbrev::elidePrefixes(const QStringList &texts,
212 const QFontMetrics &metrics,
213 int targetWidthReduction,
214 QString ellipsis)
215 {
216 if (texts.empty()) return texts;
217 int plen = getPrefixLength(texts);
218 int fl = getFuzzLength(ellipsis);
219 if (plen < fl) return texts;
220
221 QString prefix = texts[0].left(plen);
222 int pwid = metrics.width(prefix);
223 int twid = pwid - targetWidthReduction;
224 if (twid < metrics.width(ellipsis) * 2) twid = metrics.width(ellipsis) * 2;
225 prefix = abbreviate(prefix, metrics, twid, ElideEnd, ellipsis);
226
227 QStringList results;
228 for (int i = 0; i < texts.size(); ++i) {
229 results.push_back
230 (prefix + texts[i].right(texts[i].length() - plen));
231 }
232 return results;
233 }
234
235 static bool
236 havePrefix(QString prefix, const QStringList &texts)
237 {
238 for (int i = 1; i < texts.size(); ++i) {
239 if (!texts[i].startsWith(prefix)) return false;
240 }
241 return true;
242 }
243
244 int
245 TextAbbrev::getPrefixLength(const QStringList &texts)
246 {
247 QString reference = texts[0];
248
249 if (reference == "" || havePrefix(reference, texts)) {
250 return reference.length();
251 }
252
253 int candidate = reference.length();
254 QString splitChars(";:,./#-!()$_+=[]{}\\");
255
256 while (--candidate > 1) {
257 if (splitChars.contains(reference[candidate])) {
258 if (havePrefix(reference.left(candidate), texts)) {
259 break;
260 }
261 }
262 }
263
264 // std::cerr << "TextAbbrev::getPrefixLength: prefix length is " << candidate << std::endl;
265 // for (int i = 0; i < texts.size(); ++i) {
266 // std::cerr << texts[i].left(candidate).toStdString() << "|" << texts[i].right(texts[i].length() - candidate).toStdString() << std::endl;
267 // }
268
269 return candidate;
270 }
271