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