changeset 360:d58701996fae

* Update remaining editable layers to support proper realignment on copy/paste * Permit pasting when no suitable layer is current: create a new layer on paste * Add preference for showing the splash screen or not * Rename spectrogram smoothing prefs (partly following Craig's suggestions)
author Chris Cannam
date Wed, 06 Feb 2008 14:15:09 +0000
parents 020c485aa7e0
children 67834ac56f2b
files layer/ImageLayer.cpp layer/Layer.cpp layer/Layer.h layer/LayerFactory.cpp layer/LayerFactory.h layer/NoteLayer.cpp layer/TextLayer.cpp layer/TimeInstantLayer.cpp layer/TimeValueLayer.cpp widgets/PropertyStack.cpp
diffstat 10 files changed, 259 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/layer/ImageLayer.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/ImageLayer.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -30,6 +30,7 @@
 #include <QInputDialog>
 #include <QMutexLocker>
 #include <QTextStream>
+#include <QMessageBox>
 
 #include <iostream>
 #include <cmath>
@@ -812,9 +813,8 @@
     for (ImageModel::PointList::iterator i = points.begin();
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
-            //!!! inadequate
             Clipboard::Point point(i->frame, i->label);
-            point.setReferenceFrame(m_model->alignToReference(i->frame));
+            point.setReferenceFrame(alignToReference(v, i->frame));
             to.addPoint(point);
         }
     }
@@ -827,6 +827,25 @@
 
     const Clipboard::PointList &points = from.getPoints();
 
+    bool realign = false;
+
+    if (clipboardHasDifferentAlignment(v, from)) {
+
+        QMessageBox::StandardButton button =
+            QMessageBox::question(v, tr("Re-align pasted items?"),
+                                  tr("The items you are pasting came from a layer with different source material from this one.  Do you want to re-align them in time, to match the source material for this layer?"),
+                                  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+                                  QMessageBox::Yes);
+
+        if (button == QMessageBox::Cancel) {
+            return false;
+        }
+
+        if (button == QMessageBox::Yes) {
+            realign = true;
+        }
+    }
+
     ImageModel::EditCommand *command =
 	new ImageModel::EditCommand(m_model, tr("Paste"));
 
@@ -834,10 +853,23 @@
          i != points.end(); ++i) {
         
         if (!i->haveFrame()) continue;
+
         size_t frame = 0;
-        if (frameOffset > 0 || -frameOffset < i->getFrame()) {
-            frame = i->getFrame() + frameOffset;
+
+        if (!realign) {
+            
+            frame = i->getFrame();
+
+        } else {
+
+            if (i->haveReferenceFrame()) {
+                frame = i->getReferenceFrame();
+                frame = alignFromReference(v, frame);
+            } else {
+                frame = i->getFrame();
+            }
         }
+
         ImageModel::Point newPoint(frame);
 
         //!!! inadequate
--- a/layer/Layer.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/Layer.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -184,6 +184,82 @@
 }
 
 bool
+Layer::clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const
+{
+    // Notes on pasting to an aligned layer:
+    // 
+    // Each point may have a reference frame that may differ from the
+    // point's given frame (in its source model).  If it has no
+    // reference frame, we have to assume the source model was not
+    // aligned or was the reference model: when cutting or copying
+    // points from a layer, we must always set their reference frame
+    // correctly if we are aligned.
+    // 
+    // When pasting:
+    // - if point's reference and aligned frames differ:
+    //   - if this layer is aligned:
+    //     - if point's aligned frame matches this layer's aligned version
+    //       of point's reference frame:
+    //       - we can paste at reference frame or our frame
+    //     - else
+    //       - we can paste at reference frame, result of aligning reference
+    //         frame in our model, or literal source frame
+    //   - else
+    //     - we can paste at reference (our) frame, or literal source frame
+    // - else
+    //   - if this layer is aligned:
+    //     - we can paste at reference (point's only available) frame,
+    //       or result of aligning reference frame in our model
+    //   - else
+    //     - we can only paste at reference frame
+    // 
+    // Which of these alternatives are useful?
+    //
+    // Example: we paste between two tracks that are aligned to the
+    // same reference, and the points are at 10s and 20s in the source
+    // track, corresponding to 5s and 10s in the reference but 20s and
+    // 30s in the target track.
+    // 
+    // The obvious default is to paste at 20s and 30s; if we aren't
+    // doing that, would it be better to paste at 5s and 10s or at 10s
+    // and 20s?  We probably don't ever want to do the former, do we?
+    // We either want to be literal all the way through, or aligned
+    // all the way through.
+
+    for (Clipboard::PointList::const_iterator i = clip.getPoints().begin();
+         i != clip.getPoints().end(); ++i) {
+
+        // In principle, we want to know whether the aligned version
+        // of the reference frame in our layer is the same as the
+        // source frame contained in the clipboard point.  However,
+        // because of rounding during alignment, that won't
+        // necessarily be the case even if the clipboard point came
+        // from our layer!  What we need to check is whether, if we
+        // aligned the clipboard point's frame back to the reference
+        // using this layer's alignment, we would obtain the same
+        // reference frame as that for the clipboard point.
+
+        // What if the clipboard point has no reference frame?  Then
+        // we have to treat it as having its own frame as the
+        // reference (i.e. having been copied from the reference
+        // model).
+        
+        long sourceFrame = i->getFrame();
+        long referenceFrame = sourceFrame;
+        if (i->haveReferenceFrame()) {
+            referenceFrame = i->getReferenceFrame();
+        }
+        long myMappedFrame = alignToReference(v, sourceFrame);
+
+//        std::cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->haveReferenceFrame() << "), myMappedFrame = " << myMappedFrame << std::endl;
+
+        if (myMappedFrame != referenceFrame) return true;
+    }
+
+    return false;
+}
+
+bool
 Layer::MeasureRect::operator<(const MeasureRect &mr) const
 {
     if (haveFrames) {
--- a/layer/Layer.h	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/Layer.h	Wed Feb 06 14:15:09 2008 +0000
@@ -468,6 +468,7 @@
 
     virtual size_t alignToReference(View *v, size_t frame) const;
     virtual size_t alignFromReference(View *v, size_t frame) const;
+    bool clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const;
 
     struct MeasureRect {
 
--- a/layer/LayerFactory.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/LayerFactory.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -28,6 +28,8 @@
 #include "SliceLayer.h"
 #include "SliceableLayer.h"
 
+#include "base/Clipboard.h"
+
 #include "data/model/RangeSummarisableTimeValueModel.h"
 #include "data/model/DenseTimeValueModel.h"
 #include "data/model/SparseOneDimensionalModel.h"
@@ -482,3 +484,24 @@
     settings.endGroup();
 }
 
+LayerFactory::LayerType
+LayerFactory::getLayerTypeForClipboardContents(const Clipboard &clip)
+{
+    const Clipboard::PointList &contents = clip.getPoints();
+
+    bool haveFrame = false;
+    bool haveValue = false;
+    bool haveDuration = false;
+
+    for (Clipboard::PointList::const_iterator i = contents.begin();
+         i != contents.end(); ++i) {
+        if (i->haveFrame()) haveFrame = true;
+        if (i->haveValue()) haveValue = true;
+        if (i->haveDuration()) haveDuration = true;
+    }
+
+    if (haveFrame && haveValue && haveDuration) return Notes;
+    if (haveFrame && haveValue) return TimeValues;
+    return TimeInstants;
+}
+    
--- a/layer/LayerFactory.h	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/LayerFactory.h	Wed Feb 06 14:15:09 2008 +0000
@@ -21,6 +21,7 @@
 
 class Layer;
 class Model;
+class Clipboard;
 
 class LayerFactory
 {
@@ -76,6 +77,8 @@
     QString getLayerTypeName(LayerType);
     LayerType getLayerTypeForName(QString);
 
+    LayerType getLayerTypeForClipboardContents(const Clipboard &);
+
 protected:
     template <typename LayerClass, typename ModelClass>
     bool trySetModel(Layer *layerBase, Model *modelBase) {
--- a/layer/NoteLayer.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/NoteLayer.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -33,6 +33,7 @@
 #include <QPainterPath>
 #include <QMouseEvent>
 #include <QTextStream>
+#include <QMessageBox>
 
 #include <iostream>
 #include <cmath>
@@ -927,7 +928,7 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label);
-            point.setReferenceFrame(m_model->alignToReference(i->frame));
+            point.setReferenceFrame(alignToReference(v, i->frame));
             to.addPoint(point);
         }
     }
@@ -940,6 +941,25 @@
 
     const Clipboard::PointList &points = from.getPoints();
 
+    bool realign = false;
+
+    if (clipboardHasDifferentAlignment(v, from)) {
+
+        QMessageBox::StandardButton button =
+            QMessageBox::question(v, tr("Re-align pasted items?"),
+                                  tr("The items you are pasting came from a layer with different source material from this one.  Do you want to re-align them in time, to match the source material for this layer?"),
+                                  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+                                  QMessageBox::Yes);
+
+        if (button == QMessageBox::Cancel) {
+            return false;
+        }
+
+        if (button == QMessageBox::Yes) {
+            realign = true;
+        }
+    }
+
     NoteModel::EditCommand *command =
 	new NoteModel::EditCommand(m_model, tr("Paste"));
 
@@ -948,9 +968,21 @@
         
         if (!i->haveFrame()) continue;
         size_t frame = 0;
-        if (frameOffset > 0 || -frameOffset < i->getFrame()) {
-            frame = i->getFrame() + frameOffset;
+
+        if (!realign) {
+            
+            frame = i->getFrame();
+
+        } else {
+
+            if (i->haveReferenceFrame()) {
+                frame = i->getReferenceFrame();
+                frame = alignFromReference(v, frame);
+            } else {
+                frame = i->getFrame();
+            }
         }
+
         NoteModel::Point newPoint(frame);
   
         if (i->haveLabel()) newPoint.label = i->getLabel();
--- a/layer/TextLayer.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/TextLayer.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -27,6 +27,7 @@
 #include <QMouseEvent>
 #include <QInputDialog>
 #include <QTextStream>
+#include <QMessageBox>
 
 #include <iostream>
 #include <cmath>
@@ -682,7 +683,7 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->height, i->label);
-            point.setReferenceFrame(m_model->alignToReference(i->frame));
+            point.setReferenceFrame(alignToReference(v, i->frame));
             to.addPoint(point);
         }
     }
@@ -695,6 +696,25 @@
 
     const Clipboard::PointList &points = from.getPoints();
 
+    bool realign = false;
+
+    if (clipboardHasDifferentAlignment(v, from)) {
+
+        QMessageBox::StandardButton button =
+            QMessageBox::question(v, tr("Re-align pasted items?"),
+                                  tr("The items you are pasting came from a layer with different source material from this one.  Do you want to re-align them in time, to match the source material for this layer?"),
+                                  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+                                  QMessageBox::Yes);
+
+        if (button == QMessageBox::Cancel) {
+            return false;
+        }
+
+        if (button == QMessageBox::Yes) {
+            realign = true;
+        }
+    }
+
     TextModel::EditCommand *command =
 	new TextModel::EditCommand(m_model, tr("Paste"));
 
@@ -713,9 +733,21 @@
         
         if (!i->haveFrame()) continue;
         size_t frame = 0;
-        if (frameOffset > 0 || -frameOffset < i->getFrame()) {
-            frame = i->getFrame() + frameOffset;
+        
+        if (!realign) {
+            
+            frame = i->getFrame();
+
+        } else {
+
+            if (i->haveReferenceFrame()) {
+                frame = i->getReferenceFrame();
+                frame = alignFromReference(v, frame);
+            } else {
+                frame = i->getFrame();
+            }
         }
+
         TextModel::Point newPoint(frame);
 
         if (i->haveValue()) {
--- a/layer/TimeInstantLayer.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/TimeInstantLayer.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -30,6 +30,7 @@
 #include <QPainter>
 #include <QMouseEvent>
 #include <QTextStream>
+#include <QMessageBox>
 
 #include <iostream>
 #include <cmath>
@@ -723,148 +724,36 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->label);
-
-    //!!! This fails, because simply being "on the same pane as" a
-    // particular model is not enough to give this layer the same
-    // alignment as it.  If it was generated by deriving from another
-    // layer's model, that would be... but it wasn't necessarily
-
             point.setReferenceFrame(alignToReference(v, i->frame));
-
-            std::cerr << "TimeInstantLayer::copy: frame = " << i->frame << ", reference frame = " << point.getReferenceFrame() << std::endl;
-
             to.addPoint(point);
         }
     }
 }
 
 bool
-TimeInstantLayer::clipboardAlignmentDiffers(View *v, const Clipboard &clip) const
-{
-    //!!! hoist -- all pastable layers will need this
-
-    //!!! This fails, because simply being "on the same pane as" a
-    // particular model is not enough to give this layer the same
-    // alignment as it.  If it was generated by deriving from another
-    // layer's model, that would be... but it wasn't necessarily
-
-    if (!m_model) return false;
-
-    std::cerr << "TimeInstantLayer::clipboardAlignmentDiffers" << std::endl;
-
-    for (Clipboard::PointList::const_iterator i = clip.getPoints().begin();
-         i != clip.getPoints().end(); ++i) {
-
-        // In principle, we want to know whether the aligned version
-        // of the reference frame in our model is the same as the
-        // source frame contained in the clipboard point.  However,
-        // because of rounding during alignment, that won't
-        // necessarily be the case even if the clipboard point came
-        // from our model!  What we need to check is whether, if we
-        // aligned the clipboard point's frame back to the reference
-        // using this model's alignment, we would obtain the same
-        // reference frame as that for the clipboard point.
-
-        // What if the clipboard point has no reference frame?  Then
-        // we have to treat it as having its own frame as the
-        // reference (i.e. having been copied from the reference
-        // model).
-        
-        long sourceFrame = i->getFrame();
-        long referenceFrame = sourceFrame;
-        if (i->haveReferenceFrame()) {
-            referenceFrame = i->getReferenceFrame();
-        }
-        long myMappedFrame = alignToReference(v, sourceFrame);
-
-        std::cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->haveReferenceFrame() << "), myMappedFrame = " << myMappedFrame << std::endl;
-
-        if (myMappedFrame != referenceFrame) return true;
-    }
-
-    return false;
-}
-
-bool
 TimeInstantLayer::paste(View *v, const Clipboard &from, int frameOffset, bool)
 {
     if (!m_model) return false;
 
     const Clipboard::PointList &points = from.getPoints();
 
-    //!!!
-    
-    // Clipboard::haveReferenceFrames() will return true if any of the
-    // items in the clipboard came from an aligned, non-reference model.
-    
-    // We need to know whether these points came from our model or not
-    // -- if they did, we don't want to align them.
-
-    // If they didn't come from our model, and if reference frames are
-    // available, then we want to offer to align them.  If reference
-    // frames are unavailable but they came from the reference model,
-    // we want to offer to align them too.
-
-
-    //!!!
-
-    // Each point may have a reference frame that may differ from the
-    // point's given frame (in its source model).  If it has no
-    // reference frame, we have to assume the source model was not
-    // aligned or was the reference model: when cutting or copying
-    // points from a layer, we must always set their reference frame
-    // correctly if we are aligned.
-    // 
-    // When pasting:
-    // - if point's reference and aligned frames differ:
-    //   - if this layer is aligned:
-    //     - if point's aligned frame matches this layer's aligned version
-    //       of point's reference frame:
-    //       - we can paste at reference frame or our frame
-    //     - else
-    //       - we can paste at reference frame, result of aligning reference
-    //         frame in our model, or literal source frame
-    //   - else
-    //     - we can paste at reference (our) frame, or literal source frame
-    // - else
-    //   - if this layer is aligned:
-    //     - we can paste at reference (point's only available) frame,
-    //       or result of aligning reference frame in our model
-    //   - else
-    //     - we can only paste at reference frame
-    // 
-    // Which of these alternatives are useful?
-    //
-    // Example: we paste between two tracks that are aligned to the
-    // same reference, and the points are at 10s and 20s in the source
-    // track, corresponding to 5s and 10s in the reference but 20s and
-    // 30s in the target track.
-    // 
-    // The obvious default is to paste at 20s and 30s; if we aren't
-    // doing that, would it be better to paste at 5s and 10s or at 10s
-    // and 20s?  We probably don't ever want to do the former, do we?
-    // We either want to be literal all the way through, or aligned
-    // all the way through.
-
     bool realign = false;
 
-    if (clipboardAlignmentDiffers(v, from)) {
+    if (clipboardHasDifferentAlignment(v, from)) {
 
-        std::cerr << "Offer alignment option..." << std::endl;
+        QMessageBox::StandardButton button =
+            QMessageBox::question(v, tr("Re-align pasted instants?"),
+                                  tr("The instants you are pasting came from a layer with different source material from this one.  Do you want to re-align them in time, to match the source material for this layer?"),
+                                  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+                                  QMessageBox::Yes);
 
-        QStringList options;
-        options << "Use times unchanged from the original layer";
-        options << "Re-align times to match the same points in the reference layer";
+        if (button == QMessageBox::Cancel) {
+            return false;
+        }
 
-        bool ok = false;
-
-        QString selected = ListInputDialog::getItem
-            (0, tr("Choose alignment"),
-             tr("The points you are pasting originated in a layer with different alignment from the current layer.  Would you like to re-align them when pasting?"),
-             options, 0, &ok);
-        if (!ok) return false;
-
-        if (selected == options[1]) realign = true;
+        if (button == QMessageBox::Yes) {
+            realign = true;
+        }
     }
 
     SparseOneDimensionalModel::EditCommand *command =
--- a/layer/TimeValueLayer.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/layer/TimeValueLayer.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -36,6 +36,7 @@
 #include <QMouseEvent>
 #include <QRegExp>
 #include <QTextStream>
+#include <QMessageBox>
 #include <QInputDialog>
 
 #include <iostream>
@@ -1196,7 +1197,7 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->value, i->label);
-            point.setReferenceFrame(m_model->alignToReference(i->frame));
+            point.setReferenceFrame(alignToReference(v, i->frame));
             to.addPoint(point);
         }
     }
@@ -1210,6 +1211,25 @@
 
     const Clipboard::PointList &points = from.getPoints();
 
+    bool realign = false;
+
+    if (clipboardHasDifferentAlignment(v, from)) {
+
+        QMessageBox::StandardButton button =
+            QMessageBox::question(v, tr("Re-align pasted items?"),
+                                  tr("The items you are pasting came from a layer with different source material from this one.  Do you want to re-align them in time, to match the source material for this layer?"),
+                                  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+                                  QMessageBox::Yes);
+
+        if (button == QMessageBox::Cancel) {
+            return false;
+        }
+
+        if (button == QMessageBox::Yes) {
+            realign = true;
+        }
+    }
+
     SparseTimeValueModel::EditCommand *command =
 	new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
 
@@ -1324,10 +1344,23 @@
          i != points.end(); ++i) {
         
         if (!i->haveFrame()) continue;
+
         size_t frame = 0;
-        if (frameOffset > 0 || -frameOffset < i->getFrame()) {
-            frame = i->getFrame() + frameOffset;
+
+        if (!realign) {
+            
+            frame = i->getFrame();
+
+        } else {
+
+            if (i->haveReferenceFrame()) {
+                frame = i->getReferenceFrame();
+                frame = alignFromReference(v, frame);
+            } else {
+                frame = i->getFrame();
+            }
         }
+
         SparseTimeValueModel::Point newPoint(frame);
   
         if (i->haveLabel()) {
@@ -1349,7 +1382,7 @@
 
     command->finish();
     return true;
-    }
+}
 
 void
 TimeValueLayer::toXml(QTextStream &stream,
--- a/widgets/PropertyStack.cpp	Wed Feb 06 12:49:49 2008 +0000
+++ b/widgets/PropertyStack.cpp	Wed Feb 06 14:15:09 2008 +0000
@@ -114,18 +114,6 @@
 
         shortName = QString("&%1 %2").arg(i + 1).arg(shortName);
 
-//!!! We'll comment this out until it's been tested with Qt 4.3.3
-#ifdef Q_WS_MAC___NOT_DEFINED
-
-        // Qt 4.2 on OS/X doesn't show the icons in the tab bar, and
-        // I'm not sure why -- use labels instead
-
-        addTab(box, shortName);
-
-#else
-
-        // Icons on other platforms
-
 	QString iconName = container->getPropertyContainerIconName();
 
         QIcon icon(IconLoader().load(iconName));
@@ -136,8 +124,6 @@
 	    setTabToolTip(i, name);
 	}
 
-#endif
-
 	m_boxes.push_back(box);
     }