changeset 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 20028c634494
children 557e00480279
files base/TextAbbrev.cpp base/TextAbbrev.h base/base.pro
diffstat 3 files changed, 374 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base/TextAbbrev.cpp	Fri Aug 10 16:36:50 2007 +0000
@@ -0,0 +1,264 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006-2007 Chris Cannam and QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "TextAbbrev.h"
+
+#include <QFontMetrics>
+#include <QApplication>
+
+QString
+TextAbbrev::getDefaultEllipsis()
+{
+    return "...";
+}
+
+int
+TextAbbrev::getFuzzLength(QString ellipsis)
+{
+    int len = ellipsis.length();
+    if (len < 3) return len + 3;
+    else if (len > 5) return len + 5;
+    else return len * 2;
+}
+
+int
+TextAbbrev::getFuzzWidth(const QFontMetrics &metrics, QString ellipsis)
+{
+    int width = metrics.width(ellipsis);
+    return width * 2;
+}
+
+QString
+TextAbbrev::abbreviateTo(QString text, int characters, Policy policy,
+                         QString ellipsis)
+{
+    switch (policy) {
+
+    case ElideEnd:
+    case ElideEndAndCommonPrefixes:
+        text = text.left(characters) + ellipsis;
+        break;
+        
+    case ElideStart:
+        text = ellipsis + text.right(characters);
+        break;
+
+    case ElideMiddle:
+        if (characters > 2) {
+            text = text.left(characters/2 + 1) + ellipsis
+                + text.right(characters - (characters/2 + 1));
+        } else {
+            text = text.left(characters) + ellipsis;
+        }
+        break;
+    }
+
+    return text;
+}
+
+QString
+TextAbbrev::abbreviate(QString text, int maxLength, Policy policy, bool fuzzy,
+                       QString ellipsis)
+{
+    if (ellipsis == "") ellipsis = getDefaultEllipsis();
+    int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
+    if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
+    if (text.length() <= maxLength + fl) return text;
+
+    int truncated = maxLength - ellipsis.length();
+    return abbreviateTo(text, truncated, policy, ellipsis);
+}
+
+QString
+TextAbbrev::abbreviate(QString text,
+                       const QFontMetrics &metrics, int &maxWidth,
+                       Policy policy, QString ellipsis)
+{
+    if (ellipsis == "") ellipsis = getDefaultEllipsis();
+
+    int tw = metrics.width(text);
+
+    if (tw <= maxWidth) {
+        maxWidth = tw;
+        return text;
+    }
+
+    int truncated = text.length();
+    QString original = text;
+
+    while (tw > maxWidth && truncated > 1) {
+
+        truncated--;
+
+        if (truncated > ellipsis.length()) {
+            text = abbreviateTo(original, truncated, policy, ellipsis);
+        } else {
+            break;
+        }
+
+        tw = metrics.width(text);
+    }
+
+    maxWidth = tw;
+    return text;
+}
+
+QStringList
+TextAbbrev::abbreviate(const QStringList &texts, int maxLength,
+                       Policy policy, bool fuzzy, QString ellipsis)
+{
+    if (policy == ElideEndAndCommonPrefixes &&
+        texts.size() > 1) {
+
+        if (ellipsis == "") ellipsis = getDefaultEllipsis();
+        int fl = (fuzzy ? getFuzzLength(ellipsis) : 0);
+        if (maxLength <= ellipsis.length()) maxLength = ellipsis.length() + 1;
+
+        int maxOrigLength = 0;
+        for (int i = 0; i < texts.size(); ++i) {
+            int len = texts[i].length();
+            if (len > maxOrigLength) maxOrigLength = len;
+        }
+        if (maxOrigLength <= maxLength + fl) return texts;
+
+        return abbreviate(elidePrefixes
+                          (texts, maxOrigLength - maxLength, ellipsis),
+                          maxLength, ElideEnd, fuzzy, ellipsis);
+    }
+
+    QStringList results;
+    for (int i = 0; i < texts.size(); ++i) {
+        results.push_back
+            (abbreviate(texts[i], maxLength, policy, fuzzy, ellipsis));
+    }
+    return results;
+}
+
+QStringList
+TextAbbrev::abbreviate(const QStringList &texts, const QFontMetrics &metrics,
+                       int &maxWidth, Policy policy, QString ellipsis)
+{
+    if (policy == ElideEndAndCommonPrefixes &&
+        texts.size() > 1) {
+
+        if (ellipsis == "") ellipsis = getDefaultEllipsis();
+
+        int maxOrigWidth = 0;
+        for (int i = 0; i < texts.size(); ++i) {
+            int w = metrics.width(texts[i]);
+            if (w > maxOrigWidth) maxOrigWidth = w;
+        }
+
+        return abbreviate(elidePrefixes(texts, metrics,
+                                        maxOrigWidth - maxWidth, ellipsis),
+                          metrics, maxWidth, ElideEnd, ellipsis);
+    }
+
+    QStringList results;
+    int maxAbbrWidth = 0;
+    for (int i = 0; i < texts.size(); ++i) {
+        int width = maxWidth;
+        QString abbr = abbreviate(texts[i], metrics, width, policy, ellipsis);
+        if (width > maxAbbrWidth) maxAbbrWidth = width;
+        results.push_back(abbr);
+    }
+    maxWidth = maxAbbrWidth;
+    return results;
+}
+
+QStringList
+TextAbbrev::elidePrefixes(const QStringList &texts,
+                          int targetReduction,
+                          QString ellipsis)
+{
+    if (texts.empty()) return texts;
+    int plen = getPrefixLength(texts);
+    int fl = getFuzzLength(ellipsis);
+    if (plen < fl) return texts;
+
+    QString prefix = texts[0].left(plen);
+    int truncated = plen;
+    if (plen >= targetReduction + fl) {
+        truncated = plen - targetReduction;
+    } else {
+        truncated = fl;
+    }
+    prefix = abbreviate(prefix, truncated, ElideEnd, false, ellipsis);
+
+    QStringList results;
+    for (int i = 0; i < texts.size(); ++i) {
+        results.push_back
+            (prefix + texts[i].right(texts[i].length() - plen));
+    }
+    return results;
+}
+
+QStringList
+TextAbbrev::elidePrefixes(const QStringList &texts,
+                          const QFontMetrics &metrics,
+                          int targetWidthReduction,
+                          QString ellipsis)
+{
+    if (texts.empty()) return texts;
+    int plen = getPrefixLength(texts);
+    int fl = getFuzzLength(ellipsis);
+    if (plen < fl) return texts;
+
+    QString prefix = texts[0].left(plen);
+    int pwid = metrics.width(prefix);
+    int twid = pwid - targetWidthReduction;
+    if (twid < metrics.width(ellipsis) * 2) twid = metrics.width(ellipsis) * 2;
+    prefix = abbreviate(prefix, metrics, twid, ElideEnd, ellipsis);
+
+    QStringList results;
+    for (int i = 0; i < texts.size(); ++i) {
+        results.push_back
+            (prefix + texts[i].right(texts[i].length() - plen));
+    }
+    return results;
+}
+
+static bool
+havePrefix(QString prefix, const QStringList &texts)
+{
+    for (int i = 1; i < texts.size(); ++i) {
+        if (!texts[i].startsWith(prefix)) return false;
+    }
+    return true;
+}
+
+int
+TextAbbrev::getPrefixLength(const QStringList &texts)
+{
+    QString reference = texts[0];
+
+    if (reference == "" || havePrefix(reference, texts)) {
+        return reference.length();
+    }
+
+    int candidate = reference.length();
+    QString splitChars(";:,./#-!()$_+=[]{}\\");
+
+    while (--candidate > 1) {
+        if (splitChars.contains(reference[candidate])) {
+            if (havePrefix(reference.left(candidate - 1), texts)) {
+                break;
+            }
+        }
+    }
+
+    return candidate;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base/TextAbbrev.h	Fri Aug 10 16:36:50 2007 +0000
@@ -0,0 +1,108 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006-2007 Chris Cannam and QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef _TEXT_ABBREV_H_
+#define _TEXT_ABBREV_H_
+
+#include <QString>
+#include <QStringList>
+
+class QFontMetrics;
+
+class TextAbbrev 
+{
+public:
+    enum Policy {
+        ElideEnd,
+        ElideEndAndCommonPrefixes,
+        ElideStart,
+        ElideMiddle
+    };
+
+    /**
+     * Abbreviate the given text to the given maximum length
+     * (including ellipsis), using the given abbreviation policy.  If
+     * fuzzy is true, the text will be left alone if it is "not much
+     * more than" the maximum length.
+     * 
+     * If ellipsis is non-empty, it will be used to show elisions in
+     * preference to the default (which is "...").
+     */
+    static QString abbreviate(QString text, int maxLength,
+                              Policy policy = ElideEnd,
+                              bool fuzzy = true,
+                              QString ellipsis = "");
+
+    /**
+     * Abbreviate the given text to the given maximum painted width,
+     * using the given abbreviation policy.  maxWidth is also modified
+     * so as to return the painted width of the abbreviated text.
+     *
+     * If ellipsis is non-empty, it will be used to show elisions in
+     * preference to the default (which is tr("...")).
+     */
+    static QString abbreviate(QString text,
+                              const QFontMetrics &metrics,
+                              int &maxWidth,
+                              Policy policy = ElideEnd,
+                              QString ellipsis = "");
+    
+    /**
+     * Abbreviate all of the given texts to the given maximum length,
+     * using the given abbreviation policy.  If fuzzy is true, texts
+     * that are "not much more than" the maximum length will be left
+     * alone.
+     *
+     * If ellipsis is non-empty, it will be used to show elisions in
+     * preference to the default (which is tr("...")).
+     */
+    static QStringList abbreviate(const QStringList &texts, int maxLength,
+                                  Policy policy = ElideEndAndCommonPrefixes,
+                                  bool fuzzy = true,
+                                  QString ellipsis = "");
+
+    /**
+     * Abbreviate all of the given texts to the given maximum painted
+     * width, using the given abbreviation policy.  maxWidth is also
+     * modified so as to return the maximum painted width of the
+     * abbreviated texts.
+     *
+     * If ellipsis is non-empty, it will be used to show elisions in
+     * preference to the default (which is tr("...")).
+     */
+    static QStringList abbreviate(const QStringList &texts,
+                                  const QFontMetrics &metrics,
+                                  int &maxWidth,
+                                  Policy policy = ElideEndAndCommonPrefixes,
+                                  QString ellipsis = "");
+
+protected:
+    static QString getDefaultEllipsis();
+    static int getFuzzLength(QString ellipsis);
+    static int getFuzzWidth(const QFontMetrics &metrics, QString ellipsis);
+    static QString abbreviateTo(QString text, int characters,
+                                Policy policy, QString ellipsis);
+    static QStringList elidePrefixes(const QStringList &texts,
+                                     int targetReduction,
+                                     QString ellipsis);
+    static QStringList elidePrefixes(const QStringList &texts,
+                                     const QFontMetrics &metrics,
+                                     int targetWidthReduction,
+                                     QString ellipsis);
+    static int getPrefixLength(const QStringList &texts);
+};
+
+#endif
+
--- a/base/base.pro	Thu Aug 09 16:29:29 2007 +0000
+++ b/base/base.pro	Fri Aug 10 16:36:50 2007 +0000
@@ -37,6 +37,7 @@
            Selection.h \
            StorageAdviser.h \
            TempDirectory.h \
+           TextAbbrev.h \
            Thread.h \
            UnitDatabase.h \
            Window.h \
@@ -62,6 +63,7 @@
            Selection.cpp \
            StorageAdviser.cpp \
            TempDirectory.cpp \
+           TextAbbrev.cpp \
            Thread.cpp \
            UnitDatabase.cpp \
            XmlExportable.cpp