changeset 125:999ae0f7d10c

* Change preferences dialog to ok/apply/cancel model * Make preferences persist in a config file * Change instance() to getInstance() for all singleton types * Make pasting to time-value layer with no values in clipboard ask you how to generate the values * Fix bad behaviour caused by importing "data"-type (i.e. 3d dense) model from annotation file without a fixed window size available
author Chris Cannam
date Thu, 27 Jul 2006 16:06:32 +0000
parents bd6e85b3d88b
children 0e95c127bb53
files layer/Colour3DPlotLayer.cpp layer/Colour3DPlotLayer.h layer/LayerFactory.cpp layer/LayerFactory.h layer/NoteLayer.cpp layer/NoteLayer.h layer/TextLayer.cpp layer/TextLayer.h layer/TimeInstantLayer.cpp layer/TimeInstantLayer.h layer/TimeRulerLayer.h layer/TimeValueLayer.cpp layer/TimeValueLayer.h
diffstat 13 files changed, 293 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.cpp	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/Colour3DPlotLayer.cpp	Thu Jul 27 16:06:32 2006 +0000
@@ -26,6 +26,8 @@
 
 #include <cassert>
 
+//#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
+
 
 Colour3DPlotLayer::Colour3DPlotLayer() :
     Layer(),
@@ -170,7 +172,9 @@
 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const
 {
 //    Profiler profiler("Colour3DPlotLayer::paint");
-//    std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl;
+#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
+    std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl;
+#endif
 
     //!!! This doesn't yet accommodate the fact that the model may
     //have a different sample rate from an underlying model.  At the
@@ -272,10 +276,10 @@
     int sw = sx1 - sx0;
     int sh = m_model->getYBinCount();
 
-/*
+#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
     std::cerr << "Colour3DPlotLayer::paint: w " << w << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sw << ", sh " << sh << std::endl;
     std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", window size " << m_model->getWindowSize() << std::endl;
-*/
+#endif
 
     QPoint illuminatePos;
     bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
@@ -321,8 +325,10 @@
 		}
 	    }
             
-//            std::cout << "rect " << rx0 << "," << (ry0 - h / sh - 1) << " "
-//                      << w << "x" << (h / sh + 1) << std::endl;
+#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
+            std::cerr << "rect " << rx0 << "," << (ry0 - h / sh - 1) << " "
+                      << w << "x" << (h / sh + 1) << std::endl;
+#endif
 
 	    paint.drawRect(r);
 
--- a/layer/Colour3DPlotLayer.h	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/Colour3DPlotLayer.h	Thu Jul 27 16:06:32 2006 +0000
@@ -77,7 +77,7 @@
     virtual void setProperty(const PropertyName &, int value);
 */
 
-    void setProperties(const QXmlAttributes &attributes) { }
+    void setProperties(const QXmlAttributes &) { }
     
 protected slots:
     void cacheInvalid();
--- a/layer/LayerFactory.cpp	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/LayerFactory.cpp	Thu Jul 27 16:06:32 2006 +0000
@@ -36,7 +36,7 @@
 LayerFactory::m_instance = new LayerFactory;
 
 LayerFactory *
-LayerFactory::instance()
+LayerFactory::getInstance()
 {
     return m_instance;
 }
--- a/layer/LayerFactory.h	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/LayerFactory.h	Thu Jul 27 16:06:32 2006 +0000
@@ -45,7 +45,7 @@
 	UnknownLayer = 255
     };
 
-    static LayerFactory *instance();
+    static LayerFactory *getInstance();
     
     virtual ~LayerFactory();
 
--- a/layer/NoteLayer.cpp	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/NoteLayer.cpp	Thu Jul 27 16:06:32 2006 +0000
@@ -924,10 +924,10 @@
     }
 }
 
-void
-NoteLayer::paste(const Clipboard &from, int frameOffset)
+bool
+NoteLayer::paste(const Clipboard &from, int frameOffset, bool interactive)
 {
-    if (!m_model) return;
+    if (!m_model) return false;
 
     const Clipboard::PointList &points = from.getPoints();
 
@@ -949,12 +949,28 @@
         else newPoint.value = (m_model->getValueMinimum() +
                                m_model->getValueMaximum()) / 2;
         if (i->haveDuration()) newPoint.duration = i->getDuration();
-        else newPoint.duration = m_model->getResolution(); //!!!
+        else {
+            size_t nextFrame = frame;
+            Clipboard::PointList::const_iterator j = i;
+            for (; j != points.end(); ++j) {
+                if (!j->haveFrame()) continue;
+                if (j != i) break;
+            }
+            if (j != points.end()) {
+                nextFrame = j->getFrame();
+            }
+            if (nextFrame == frame) {
+                newPoint.duration = m_model->getResolution();
+            } else {
+                newPoint.duration = nextFrame - frame;
+            }
+        }
         
         command->addPoint(newPoint);
     }
 
     command->finish();
+    return true;
 }
 
 QString
--- a/layer/NoteLayer.h	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/NoteLayer.h	Thu Jul 27 16:06:32 2006 +0000
@@ -55,7 +55,8 @@
     virtual void deleteSelection(Selection s);
 
     virtual void copy(Selection s, Clipboard &to);
-    virtual void paste(const Clipboard &from, int frameOffset);
+    virtual bool paste(const Clipboard &from, int frameOffset,
+                       bool interactive);
 
     virtual const Model *getModel() const { return m_model; }
     void setModel(NoteModel *model);
--- a/layer/TextLayer.cpp	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/TextLayer.cpp	Thu Jul 27 16:06:32 2006 +0000
@@ -705,16 +705,26 @@
     }
 }
 
-void
-TextLayer::paste(const Clipboard &from, int frameOffset)
+bool
+TextLayer::paste(const Clipboard &from, int frameOffset, bool interactive)
 {
-    if (!m_model) return;
+    if (!m_model) return false;
 
     const Clipboard::PointList &points = from.getPoints();
 
     TextModel::EditCommand *command =
 	new TextModel::EditCommand(m_model, tr("Paste"));
 
+    float valueMin = 0.0, valueMax = 1.0;
+    for (Clipboard::PointList::const_iterator i = points.begin();
+         i != points.end(); ++i) {
+        if (i->haveValue()) {
+            if (i->getValue() < valueMin) valueMin = i->getValue();
+            if (i->getValue() > valueMax) valueMax = i->getValue();
+        }
+    }
+    if (valueMax < valueMin + 1.0) valueMax = valueMin + 1.0;
+
     for (Clipboard::PointList::const_iterator i = points.begin();
          i != points.end(); ++i) {
         
@@ -724,14 +734,26 @@
             frame = i->getFrame() + frameOffset;
         }
         TextModel::Point newPoint(frame);
-        if (i->haveValue()) newPoint.height = i->haveValue();
-        if (i->haveLabel()) newPoint.label = i->getLabel();
-        else newPoint.label = tr("New Point");
+
+        if (i->haveValue()) {
+            newPoint.height = (i->getValue() - valueMin) / (valueMax - valueMin);
+        } else {
+            newPoint.height = 0.5;
+        }
+
+        if (i->haveLabel()) {
+            newPoint.label = i->getLabel();
+        } else if (i->haveValue()) {
+            newPoint.label = QString("%1").arg(i->getValue());
+        } else {
+            newPoint.label = tr("New Point");
+        }
         
         command->addPoint(newPoint);
     }
 
     command->finish();
+    return true;
 }
 
 QString
--- a/layer/TextLayer.h	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/TextLayer.h	Thu Jul 27 16:06:32 2006 +0000
@@ -53,7 +53,8 @@
     virtual void deleteSelection(Selection s);
 
     virtual void copy(Selection s, Clipboard &to);
-    virtual void paste(const Clipboard &from, int frameOffset);
+    virtual bool paste(const Clipboard &from, int frameOffset,
+                       bool interactive);
 
     virtual void editOpen(View *, QMouseEvent *); // on double-click
 
--- a/layer/TimeInstantLayer.cpp	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/TimeInstantLayer.cpp	Thu Jul 27 16:06:32 2006 +0000
@@ -721,10 +721,10 @@
     }
 }
 
-void
-TimeInstantLayer::paste(const Clipboard &from, int frameOffset)
+bool
+TimeInstantLayer::paste(const Clipboard &from, int frameOffset, bool interactive)
 {
-    if (!m_model) return;
+    if (!m_model) return false;
 
     const Clipboard::PointList &points = from.getPoints();
 
@@ -740,12 +740,17 @@
             frame = i->getFrame() + frameOffset;
         }
         SparseOneDimensionalModel::Point newPoint(frame);
-        if (i->haveLabel()) newPoint.label = i->getLabel();
+        if (i->haveLabel()) {
+            newPoint.label = i->getLabel();
+        } else if (i->haveValue()) {
+            newPoint.label = QString("%1").arg(i->getValue());
+        }
         
         command->addPoint(newPoint);
     }
 
     command->finish();
+    return true;
 }
 
 QString
--- a/layer/TimeInstantLayer.h	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/TimeInstantLayer.h	Thu Jul 27 16:06:32 2006 +0000
@@ -55,7 +55,8 @@
     virtual void deleteSelection(Selection s);
 
     virtual void copy(Selection s, Clipboard &to);
-    virtual void paste(const Clipboard &from, int frameOffset);
+    virtual bool paste(const Clipboard &from, int frameOffset,
+                       bool interactive);
 
     virtual const Model *getModel() const { return m_model; }
     void setModel(SparseOneDimensionalModel *model);
@@ -88,8 +89,7 @@
 
     virtual bool needsTextLabelHeight() const { return m_model->hasTextLabels(); }
 
-    virtual bool getValueExtents(float &min, float &max,
-                                 bool &log, QString &unit) const {
+    virtual bool getValueExtents(float &, float &, bool &, QString &) const {
         return false;
     }
 
--- a/layer/TimeRulerLayer.h	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/TimeRulerLayer.h	Thu Jul 27 16:06:32 2006 +0000
@@ -53,8 +53,7 @@
 					  int value) const;
     virtual void setProperty(const PropertyName &, int value);
 
-    virtual bool getValueExtents(float &min, float &max,
-                                 bool &log, QString &unit) const {
+    virtual bool getValueExtents(float &, float &, bool &, QString &) const {
         return false;
     }
 
--- a/layer/TimeValueLayer.cpp	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/TimeValueLayer.cpp	Thu Jul 27 16:06:32 2006 +0000
@@ -23,12 +23,14 @@
 #include "model/SparseTimeValueModel.h"
 
 #include "widgets/ItemEditDialog.h"
+#include "widgets/ListInputDialog.h"
 
 #include "SpectrogramLayer.h" // for optional frequency alignment
 
 #include <QPainter>
 #include <QPainterPath>
 #include <QMouseEvent>
+#include <QRegExp>
 
 #include <iostream>
 #include <cmath>
@@ -1131,16 +1133,143 @@
     }
 }
 
-void
-TimeValueLayer::paste(const Clipboard &from, int frameOffset)
+bool
+TimeValueLayer::paste(const Clipboard &from, int frameOffset,
+                      bool interactive)
 {
-    if (!m_model) return;
+    if (!m_model) return false;
 
     const Clipboard::PointList &points = from.getPoints();
 
     SparseTimeValueModel::EditCommand *command =
 	new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
 
+    enum ValueAvailability {
+        UnknownAvailability,
+        NoValues,
+        SomeValues,
+        AllValues
+    };
+    enum ValueGeneration {
+        GenerateNone,
+        GenerateFromCounter,
+        GenerateFromFrameNumber,
+        GenerateFromRealTime,
+        GenerateFromRealTimeDifference,
+        GenerateFromTempo,
+        GenerateFromExistingNeighbour,
+        GenerateFromLabels
+    };
+
+    ValueGeneration generation = GenerateNone;
+
+    bool haveUsableLabels = false;
+    bool haveExistingItems = !(m_model->isEmpty());
+
+    if (interactive) {
+
+        ValueAvailability availability = UnknownAvailability;
+
+        for (Clipboard::PointList::const_iterator i = points.begin();
+             i != points.end(); ++i) {
+        
+            if (!i->haveFrame()) continue;
+
+            if (availability == UnknownAvailability) {
+                if (i->haveValue()) availability = AllValues;
+                else availability = NoValues;
+                continue;
+            }
+
+            if (i->haveValue()) {
+                if (availability == NoValues) {
+                    availability = SomeValues;
+                }
+            } else {
+                if (availability == AllValues) {
+                    availability = SomeValues;
+                }
+            }
+
+            if (!haveUsableLabels) {
+                if (i->haveLabel()) {
+                    if (i->getLabel().contains(QRegExp("[0-9]"))) {
+                        haveUsableLabels = true;
+                    }
+                }
+            }
+
+            if (availability == SomeValues && haveUsableLabels) break;
+        }
+
+        if (availability == NoValues || availability == SomeValues) {
+            
+            QString text;
+            if (availability == NoValues) {
+                text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?");
+            } else {
+                text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?");
+            }
+
+            QStringList options;
+            std::vector<int> genopts;
+
+            options << tr("Zero for all items");
+            genopts.push_back(int(GenerateNone));
+
+            options << tr("Whole numbers counting from 1");
+            genopts.push_back(int(GenerateFromCounter));
+
+            options << tr("Item's audio sample frame number");
+            genopts.push_back(int(GenerateFromFrameNumber));
+
+            options << tr("Item's time in seconds");
+            genopts.push_back(int(GenerateFromRealTime));
+
+            options << tr("Duration from the item to the following item");
+            genopts.push_back(int(GenerateFromRealTimeDifference));
+
+            options << tr("Tempo in bpm derived from the duration");
+            genopts.push_back(int(GenerateFromTempo));
+
+            if (haveExistingItems) {
+                options << tr("Value of the nearest existing item");
+                genopts.push_back(int(GenerateFromExistingNeighbour));
+            }
+
+            if (haveUsableLabels) {
+                options << tr("Value extracted from the item's label (where possible)");
+                genopts.push_back(int(GenerateFromLabels));
+            }
+
+
+            static int prevSelection = 0;
+
+            bool ok = false;
+            QString selected = ListInputDialog::getItem
+                (0, tr("Choose value calculation"),
+                 text, options, prevSelection, &ok);
+
+            if (!ok) return false;
+            int selection = 0;
+            generation = GenerateNone;
+
+            for (QStringList::const_iterator i = options.begin();
+                 i != options.end(); ++i) {
+                if (selected == *i) {
+                    generation = ValueGeneration(genopts[selection]);
+                    break;
+                }
+                ++selection;
+            }
+
+            prevSelection = selection;
+        }
+    }
+
+    int counter = 1;
+    float prevBpm = 120.f;
+
     for (Clipboard::PointList::const_iterator i = points.begin();
          i != points.end(); ++i) {
         
@@ -1151,15 +1280,91 @@
         }
         SparseTimeValueModel::Point newPoint(frame);
   
-        if (i->haveLabel()) newPoint.label = i->getLabel();
-        if (i->haveValue()) newPoint.value = i->getValue();
-        else newPoint.value = (m_model->getValueMinimum() +
-                               m_model->getValueMaximum()) / 2;
+        if (i->haveLabel()) {
+            newPoint.label = i->getLabel();
+        } else if (i->haveValue()) {
+            newPoint.label = QString("%1").arg(i->getValue());
+        }
+
+        if (i->haveValue()) {
+            newPoint.value = i->getValue();
+        } else {
+            
+            switch (generation) {
+
+            case GenerateNone:
+                newPoint.value = 0;
+                break;
+
+            case GenerateFromCounter:
+                newPoint.value = counter;
+                break;
+
+            case GenerateFromFrameNumber:
+                newPoint.value = frame;
+                break;
+
+            case GenerateFromRealTime: 
+                newPoint.value = float(frame) / float(m_model->getSampleRate());
+                break;
+
+            case GenerateFromRealTimeDifference:
+            case GenerateFromTempo:
+            {
+                size_t nextFrame = frame;
+                Clipboard::PointList::const_iterator j = i;
+                for (; j != points.end(); ++j) {
+                    if (!j->haveFrame()) continue;
+                    if (j != i) break;
+                }
+                if (j != points.end()) {
+                    nextFrame = j->getFrame();
+                }
+                if (generation == GenerateFromRealTimeDifference) {
+                    newPoint.value = float(nextFrame - frame) /
+                        float(m_model->getSampleRate());
+                } else {
+                    float bpm = prevBpm;
+                    if (nextFrame > frame) {
+                        bpm = (60.f * m_model->getSampleRate()) /
+                            (nextFrame - frame);
+                    }
+                    newPoint.value = bpm;
+                    prevBpm = bpm;
+                }
+                break;
+            }
+
+            case GenerateFromExistingNeighbour:
+            {
+                SparseTimeValueModel::PointList points = 
+                    m_model->getPoints(frame);
+                if (points.empty()) points = m_model->getPreviousPoints(frame);
+                if (points.empty()) points = m_model->getNextPoints(frame);
+                if (points.empty()) {
+                    newPoint.value = 0.f;
+                } else {
+                    newPoint.value = points.begin()->value;
+                }
+            }
+
+            case GenerateFromLabels:
+                if (i->haveLabel()) {
+                    // more forgiving than QString::toFloat()
+                    newPoint.value = atof(i->getLabel().toLocal8Bit());
+                } else {
+                    newPoint.value = 0.f;
+                }
+            }
+        }
         
         command->addPoint(newPoint);
+        
+        ++counter;
     }
 
     command->finish();
+    return true;
 }
 
 QString
--- a/layer/TimeValueLayer.h	Wed Jul 26 16:48:07 2006 +0000
+++ b/layer/TimeValueLayer.h	Thu Jul 27 16:06:32 2006 +0000
@@ -58,7 +58,8 @@
     virtual void deleteSelection(Selection s);
 
     virtual void copy(Selection s, Clipboard &to);
-    virtual void paste(const Clipboard &from, int frameOffset);
+    virtual bool paste(const Clipboard &from, int frameOffset,
+                       bool interactive);
 
     virtual const Model *getModel() const { return m_model; }
     void setModel(SparseTimeValueModel *model);