annotate textabbrev.cpp @ 50:c76782c14371

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