comparison base/TextAbbrev.cpp @ 286:20097c32d15d

* Better abbreviation modes for layer names in pane (and input model combo of plugin parameter dialog) * Avoid crash when loading SV file containing model derived from nonexistent model (shouldn't happen of course, but see bug #1771769) * Remember last-used input model in plugin parameter dialog * Don't override a layer colour loaded from a session file with the generated default colour when attaching it to a view
author Chris Cannam
date Fri, 10 Aug 2007 16:36:50 +0000
parents
children 2c1e57ad86e7
comparison
equal deleted inserted replaced
285:20028c634494 286:20097c32d15d
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 QString
22 TextAbbrev::getDefaultEllipsis()
23 {
24 return "...";
25 }
26
27 int
28 TextAbbrev::getFuzzLength(QString ellipsis)
29 {
30 int len = ellipsis.length();
31 if (len < 3) return len + 3;
32 else if (len > 5) return len + 5;
33 else return len * 2;
34 }
35
36 int
37 TextAbbrev::getFuzzWidth(const QFontMetrics &metrics, QString ellipsis)
38 {
39 int width = metrics.width(ellipsis);
40 return width * 2;
41 }
42
43 QString
44 TextAbbrev::abbreviateTo(QString text, int characters, Policy policy,
45 QString ellipsis)
46 {
47 switch (policy) {
48
49 case ElideEnd:
50 case ElideEndAndCommonPrefixes:
51 text = text.left(characters) + ellipsis;
52 break;
53
54 case ElideStart:
55 text = ellipsis + text.right(characters);
56 break;
57
58 case ElideMiddle:
59 if (characters > 2) {
60 text = text.left(characters/2 + 1) + ellipsis
61 + text.right(characters - (characters/2 + 1));
62 } else {
63 text = text.left(characters) + ellipsis;
64 }
65 break;
66 }
67
68 return text;
69 }
70
71 QString
72 TextAbbrev::abbreviate(QString text, int maxLength, Policy policy, bool fuzzy,
73 QString ellipsis)
74 {
75 if (ellipsis == "") ellipsis = getDefaultEllipsis();
76 int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
77 if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
78 if (text.length() <= maxLength + fl) return text;
79
80 int truncated = maxLength - ellipsis.length();
81 return abbreviateTo(text, truncated, policy, ellipsis);
82 }
83
84 QString
85 TextAbbrev::abbreviate(QString text,
86 const QFontMetrics &metrics, int &maxWidth,
87 Policy policy, QString ellipsis)
88 {
89 if (ellipsis == "") ellipsis = getDefaultEllipsis();
90
91 int tw = metrics.width(text);
92
93 if (tw <= maxWidth) {
94 maxWidth = tw;
95 return text;
96 }
97
98 int truncated = text.length();
99 QString original = text;
100
101 while (tw > maxWidth && truncated > 1) {
102
103 truncated--;
104
105 if (truncated > ellipsis.length()) {
106 text = abbreviateTo(original, truncated, policy, ellipsis);
107 } else {
108 break;
109 }
110
111 tw = metrics.width(text);
112 }
113
114 maxWidth = tw;
115 return text;
116 }
117
118 QStringList
119 TextAbbrev::abbreviate(const QStringList &texts, int maxLength,
120 Policy policy, bool fuzzy, QString ellipsis)
121 {
122 if (policy == ElideEndAndCommonPrefixes &&
123 texts.size() > 1) {
124
125 if (ellipsis == "") ellipsis = getDefaultEllipsis();
126 int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
127 if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
128
129 int maxOrigLength = 0;
130 for (int i = 0; i < texts.size(); ++i) {
131 int len = texts[i].length();
132 if (len > maxOrigLength) maxOrigLength = len;
133 }
134 if (maxOrigLength <= maxLength + fl) return texts;
135
136 return abbreviate(elidePrefixes
137 (texts, maxOrigLength - maxLength, ellipsis),
138 maxLength, ElideEnd, fuzzy, ellipsis);
139 }
140
141 QStringList results;
142 for (int i = 0; i < texts.size(); ++i) {
143 results.push_back
144 (abbreviate(texts[i], maxLength, policy, fuzzy, ellipsis));
145 }
146 return results;
147 }
148
149 QStringList
150 TextAbbrev::abbreviate(const QStringList &texts, const QFontMetrics &metrics,
151 int &maxWidth, Policy policy, QString ellipsis)
152 {
153 if (policy == ElideEndAndCommonPrefixes &&
154 texts.size() > 1) {
155
156 if (ellipsis == "") ellipsis = getDefaultEllipsis();
157
158 int maxOrigWidth = 0;
159 for (int i = 0; i < texts.size(); ++i) {
160 int w = metrics.width(texts[i]);
161 if (w > maxOrigWidth) maxOrigWidth = w;
162 }
163
164 return abbreviate(elidePrefixes(texts, metrics,
165 maxOrigWidth - maxWidth, ellipsis),
166 metrics, maxWidth, ElideEnd, ellipsis);
167 }
168
169 QStringList results;
170 int maxAbbrWidth = 0;
171 for (int i = 0; i < texts.size(); ++i) {
172 int width = maxWidth;
173 QString abbr = abbreviate(texts[i], metrics, width, policy, ellipsis);
174 if (width > maxAbbrWidth) maxAbbrWidth = width;
175 results.push_back(abbr);
176 }
177 maxWidth = maxAbbrWidth;
178 return results;
179 }
180
181 QStringList
182 TextAbbrev::elidePrefixes(const QStringList &texts,
183 int targetReduction,
184 QString ellipsis)
185 {
186 if (texts.empty()) return texts;
187 int plen = getPrefixLength(texts);
188 int fl = getFuzzLength(ellipsis);
189 if (plen < fl) return texts;
190
191 QString prefix = texts[0].left(plen);
192 int truncated = plen;
193 if (plen >= targetReduction + fl) {
194 truncated = plen - targetReduction;
195 } else {
196 truncated = fl;
197 }
198 prefix = abbreviate(prefix, truncated, ElideEnd, false, ellipsis);
199
200 QStringList results;
201 for (int i = 0; i < texts.size(); ++i) {
202 results.push_back
203 (prefix + texts[i].right(texts[i].length() - plen));
204 }
205 return results;
206 }
207
208 QStringList
209 TextAbbrev::elidePrefixes(const QStringList &texts,
210 const QFontMetrics &metrics,
211 int targetWidthReduction,
212 QString ellipsis)
213 {
214 if (texts.empty()) return texts;
215 int plen = getPrefixLength(texts);
216 int fl = getFuzzLength(ellipsis);
217 if (plen < fl) return texts;
218
219 QString prefix = texts[0].left(plen);
220 int pwid = metrics.width(prefix);
221 int twid = pwid - targetWidthReduction;
222 if (twid < metrics.width(ellipsis) * 2) twid = metrics.width(ellipsis) * 2;
223 prefix = abbreviate(prefix, metrics, twid, ElideEnd, ellipsis);
224
225 QStringList results;
226 for (int i = 0; i < texts.size(); ++i) {
227 results.push_back
228 (prefix + texts[i].right(texts[i].length() - plen));
229 }
230 return results;
231 }
232
233 static bool
234 havePrefix(QString prefix, const QStringList &texts)
235 {
236 for (int i = 1; i < texts.size(); ++i) {
237 if (!texts[i].startsWith(prefix)) return false;
238 }
239 return true;
240 }
241
242 int
243 TextAbbrev::getPrefixLength(const QStringList &texts)
244 {
245 QString reference = texts[0];
246
247 if (reference == "" || havePrefix(reference, texts)) {
248 return reference.length();
249 }
250
251 int candidate = reference.length();
252 QString splitChars(";:,./#-!()$_+=[]{}\\");
253
254 while (--candidate > 1) {
255 if (splitChars.contains(reference[candidate])) {
256 if (havePrefix(reference.left(candidate - 1), texts)) {
257 break;
258 }
259 }
260 }
261
262 return candidate;
263 }
264