annotate widgets/TextAbbrev.cpp @ 607:5b72899d692b

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