changeset 336:4a542ba875c2

* Improvements to layer summary dialog (LayerTree, LayerTreeDialog), & rename. It's still rather unstable though.
author Chris Cannam
date Wed, 28 Nov 2007 17:45:37 +0000
parents 2f83b6e3b8ca
children 813170c57b13
files layer/LayerFactory.cpp view/View.cpp view/View.h widgets/LayerTree.cpp widgets/LayerTree.h widgets/LayerTreeDialog.cpp widgets/LayerTreeDialog.h widgets/PluginParameterDialog.cpp widgets/PluginParameterDialog.h widgets/widgets.pro
diffstat 10 files changed, 530 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/layer/LayerFactory.cpp	Fri Nov 23 16:48:23 2007 +0000
+++ b/layer/LayerFactory.cpp	Wed Nov 28 17:45:37 2007 +0000
@@ -418,8 +418,8 @@
 	std::cerr << "LayerFactory::createLayer: Unknown layer type " 
 		  << type << std::endl;
     } else {
-	std::cerr << "LayerFactory::createLayer: Setting object name "
-		  << getLayerPresentationName(type).toStdString() << " on " << layer << std::endl;
+//	std::cerr << "LayerFactory::createLayer: Setting object name "
+//		  << getLayerPresentationName(type).toStdString() << " on " << layer << std::endl;
 	layer->setObjectName(getLayerPresentationName(type));
         setLayerDefaultProperties(type, layer);
     }
@@ -430,14 +430,14 @@
 void
 LayerFactory::setLayerDefaultProperties(LayerType type, Layer *layer)
 {
-    std::cerr << "LayerFactory::setLayerDefaultProperties: type " << type << " (name \"" << getLayerTypeName(type).toStdString() << "\"" << std::endl;
+//    std::cerr << "LayerFactory::setLayerDefaultProperties: type " << type << " (name \"" << getLayerTypeName(type).toStdString() << "\")" << std::endl;
 
     QSettings settings;
     settings.beginGroup("LayerDefaults");
     QString defaults = settings.value(getLayerTypeName(type), "").toString();
     if (defaults == "") return;
 
-    std::cerr << "defaults=\"" << defaults.toStdString() << "\"" << std::endl;
+//    std::cerr << "defaults=\"" << defaults.toStdString() << "\"" << std::endl;
 
     QString xml = layer->toXmlString();
     QDomDocument docOld, docNew;
@@ -453,9 +453,9 @@
         for (unsigned int i = 0; i < attrNodes.length(); ++i) {
             QDomAttr attr = attrNodes.item(i).toAttr();
             if (attr.isNull()) continue;
-            std::cerr << "append \"" << attr.name().toStdString()
-                      << "\" -> \"" << attr.value().toStdString() << "\""
-                      << std::endl;
+//            std::cerr << "append \"" << attr.name().toStdString()
+//                      << "\" -> \"" << attr.value().toStdString() << "\""
+//                      << std::endl;
             attrs.append(attr.name(), "", "", attr.value());
         }
         
@@ -465,9 +465,9 @@
             QDomAttr attr = attrNodes.item(i).toAttr();
             if (attr.isNull()) continue;
             if (attrs.value(attr.name()) == "") {
-                std::cerr << "append \"" << attr.name().toStdString()
-                          << "\" -> \"" << attr.value().toStdString() << "\""
-                          << std::endl;
+//                std::cerr << "append \"" << attr.name().toStdString()
+//                          << "\" -> \"" << attr.value().toStdString() << "\""
+//                          << std::endl;
                 attrs.append(attr.name(), "", "", attr.value());
             }
         }
--- a/view/View.cpp	Fri Nov 23 16:48:23 2007 +0000
+++ b/view/View.cpp	Wed Nov 28 17:45:37 2007 +0000
@@ -750,6 +750,8 @@
 	m_cache = 0;
     }
 
+    emit layerModelChanged();
+
     checkProgress(obj);
 
     update();
--- a/view/View.h	Fri Nov 23 16:48:23 2007 +0000
+++ b/view/View.h	Wed Nov 28 17:45:37 2007 +0000
@@ -271,6 +271,8 @@
     void propertyContainerSelected(PropertyContainer *pc);
     void propertyChanged(PropertyContainer::PropertyName);
 
+    void layerModelChanged();
+
     void centreFrameChanged(unsigned long frame,
                             bool globalScroll,
                             PlaybackFollowMode followMode);
--- a/widgets/LayerTree.cpp	Fri Nov 23 16:48:23 2007 +0000
+++ b/widgets/LayerTree.cpp	Wed Nov 28 17:45:37 2007 +0000
@@ -21,17 +21,34 @@
 #include "view/Pane.h"
 #include "layer/Layer.h"
 #include "data/model/Model.h"
+#include "data/model/WaveFileModel.h"
 
 #include <QIcon>
 #include <iostream>
 
 
-LayerTreeModel::LayerTreeModel(PaneStack *stack, QObject *parent) :
+ModelDataModel::ModelDataModel(PaneStack *stack, bool waveModelsOnly,
+                               QObject *parent) :
     QAbstractItemModel(parent),
-    m_stack(stack)
+    m_stack(stack),
+    m_waveModelsOnly(waveModelsOnly)
 {
-    connect(stack, SIGNAL(paneAdded()), this, SIGNAL(layoutChanged()));
-    connect(stack, SIGNAL(paneDeleted()), this, SIGNAL(layoutChanged()));
+    if (m_waveModelsOnly) {
+        m_modelTypeColumn = -1;
+        m_modelNameColumn = 0;
+        m_modelMakerColumn = 1;
+        m_modelSourceColumn = 2;
+        m_columnCount = 3;
+    } else {
+        m_modelTypeColumn = 0;
+        m_modelNameColumn = 1;
+        m_modelMakerColumn = 2;
+        m_modelSourceColumn = 3;
+        m_columnCount = 4;
+    }
+
+    connect(stack, SIGNAL(paneAdded()), this, SLOT(paneAdded()));
+    connect(stack, SIGNAL(paneDeleted()), this, SLOT(paneDeleted()));
 
     for (int i = 0; i < stack->getPaneCount(); ++i) {
         Pane *pane = stack->getPane(i);
@@ -46,6 +63,238 @@
                 this, SLOT(propertyContainerPropertyChanged(PropertyContainer *)));
         connect(pane, SIGNAL(propertyContainerNameChanged(PropertyContainer *)),
                 this, SLOT(propertyContainerPropertyChanged(PropertyContainer *)));
+        connect(pane, SIGNAL(layerModelChanged()),
+                this, SLOT(paneLayerModelChanged()));
+    }
+
+    rebuildModelSet();
+}
+
+ModelDataModel::~ModelDataModel()
+{
+}
+
+void
+ModelDataModel::rebuildModelSet()
+{
+    std::set<Model *> unfound = m_models;
+
+    for (int i = 0; i < m_stack->getPaneCount(); ++i) {
+
+        Pane *pane = m_stack->getPane(i);
+        if (!pane) continue;
+
+        for (int j = 0; j < pane->getLayerCount(); ++j) {
+
+            Layer *layer = pane->getLayer(j);
+            if (!layer) continue;
+
+            Model *model = layer->getModel();
+            if (!model) continue;
+
+            if (m_waveModelsOnly) {
+                if (!dynamic_cast<WaveFileModel *>(model)) continue;
+            }
+
+            if (m_models.find(model) == m_models.end()) {
+                connect(model, SIGNAL(aboutToBeDeleted()),
+                        this, SLOT(rebuildModelSet()));
+                m_models.insert(model);
+            } else {
+                unfound.erase(model);
+            }
+        }
+    }
+
+    for (std::set<Model *>::iterator i = unfound.begin();
+         i != unfound.end(); ++i) {
+        m_models.erase(*i);
+    }
+
+    std::cerr << "ModelDataModel::rebuildModelSet: " << m_models.size() << " models" << std::endl;
+}
+
+void
+ModelDataModel::paneAdded()
+{
+    rebuildModelSet();
+    emit layoutChanged();
+}
+
+void
+ModelDataModel::paneDeleted()
+{
+    rebuildModelSet();
+    emit layoutChanged();
+}
+
+void
+ModelDataModel::paneLayerModelChanged()
+{
+    rebuildModelSet();
+    emit layoutChanged();
+}
+
+void
+ModelDataModel::propertyContainerAdded(PropertyContainer *)
+{
+    rebuildModelSet();
+    emit layoutChanged();
+}
+
+void
+ModelDataModel::propertyContainerRemoved(PropertyContainer *)
+{
+    rebuildModelSet();
+    emit layoutChanged();
+}
+
+void
+ModelDataModel::propertyContainerSelected(PropertyContainer *)
+{
+}
+
+void
+ModelDataModel::propertyContainerPropertyChanged(PropertyContainer *pc)
+{
+}
+
+void
+ModelDataModel::playParametersAudibilityChanged(bool a)
+{
+}
+
+QVariant
+ModelDataModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid()) return QVariant();
+
+    QObject *obj = static_cast<QObject *>(index.internalPointer());
+    int row = index.row(), col = index.column();
+
+    //!!! not exactly the ideal use of a std::set
+    std::set<Model *>::iterator itr = m_models.begin();
+    for (int i = 0; i < row && itr != m_models.end(); ++i, ++itr);
+    if (itr == m_models.end()) return QVariant();
+
+    Model *model = *itr;
+
+    if (role != Qt::DisplayRole) {
+        if (m_waveModelsOnly && col == m_modelNameColumn &&
+            role == Qt::DecorationRole) {
+            // There is no meaningful icon for a model, in general --
+            // the icons we have represent layer types and it would be
+            // misleading to use them for models.  However, if we're
+            // only showing wave models, we use the waveform icon just
+            // for decorative purposes.
+            return QVariant(QIcon(QString(":/icons/waveform.png")));
+        }
+        return QVariant();
+    }
+    
+    if (col == m_modelTypeColumn) {
+        return QVariant(model->getTypeName());
+    } else if (col == m_modelNameColumn) {
+        return QVariant(model->objectName());
+    } else if (col == m_modelMakerColumn) {
+        return QVariant(model->getMaker());
+    } else if (col == m_modelSourceColumn) {
+        return QVariant(model->getLocation());
+    }        
+    
+    return QVariant();
+}
+
+bool
+ModelDataModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+    return false;
+}
+
+Qt::ItemFlags
+ModelDataModel::flags(const QModelIndex &index) const
+{
+    Qt::ItemFlags flags = Qt::ItemIsEnabled;
+    return flags;
+}
+
+QVariant
+ModelDataModel::headerData(int section,
+			   Qt::Orientation orientation,
+			   int role) const
+{
+    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+	if (section == m_modelTypeColumn) return QVariant(tr("Type"));
+	else if (section == m_modelNameColumn) return QVariant(tr("Name"));
+	else if (section == m_modelMakerColumn) return QVariant(tr("Maker"));
+	else if (section == m_modelSourceColumn) return QVariant(tr("Source"));
+    }
+
+    return QVariant();
+}
+
+QModelIndex
+ModelDataModel::index(int row, int column, const QModelIndex &parent) const
+{
+    if (!parent.isValid()) {
+        if (row >= m_models.size()) return QModelIndex();
+	return createIndex(row, column, 0);
+    }
+
+    return QModelIndex();
+}
+
+QModelIndex
+ModelDataModel::parent(const QModelIndex &index) const
+{
+    return QModelIndex();
+}
+
+int
+ModelDataModel::rowCount(const QModelIndex &parent) const
+{
+    if (!parent.isValid()) return m_models.size();
+    return 0;
+}
+
+int
+ModelDataModel::columnCount(const QModelIndex &parent) const
+{
+    return m_columnCount;
+}
+
+
+
+LayerTreeModel::LayerTreeModel(PaneStack *stack, QObject *parent) :
+    QAbstractItemModel(parent),
+    m_stack(stack)
+{
+    m_layerNameColumn = 0;
+    m_layerVisibleColumn = 1;
+    m_layerPlayedColumn = 2;
+    m_modelNameColumn = 3;
+    m_columnCount = 4;
+
+    connect(stack, SIGNAL(paneAdded()), this, SLOT(paneAdded()));
+    connect(stack, SIGNAL(paneAboutToBeDeleted(Pane *)),
+            this, SLOT(paneAboutToBeDeleted(Pane *)));
+
+    for (int i = 0; i < stack->getPaneCount(); ++i) {
+        Pane *pane = stack->getPane(i);
+        if (!pane) continue;
+        connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)),
+                this, SLOT(propertyContainerAdded(PropertyContainer *)));
+        connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)),
+                this, SLOT(propertyContainerRemoved(PropertyContainer *)));
+        connect(pane, SIGNAL(propertyContainerSelected(PropertyContainer *)),
+                this, SLOT(propertyContainerSelected(PropertyContainer *)));
+        connect(pane, SIGNAL(propertyContainerPropertyChanged(PropertyContainer *)),
+                this, SLOT(propertyContainerPropertyChanged(PropertyContainer *)));
+        connect(pane, SIGNAL(propertyContainerNameChanged(PropertyContainer *)),
+                this, SLOT(propertyContainerPropertyChanged(PropertyContainer *)));
+        connect(pane, SIGNAL(layerModelChanged()),
+                this, SLOT(paneLayerModelChanged()));
+
         for (int j = 0; j < pane->getLayerCount(); ++j) {
             Layer *layer = pane->getLayer(j);
             if (!layer) continue;
@@ -62,6 +311,20 @@
 }
 
 void
+LayerTreeModel::paneAdded()
+{
+    emit layoutChanged();
+}
+
+void
+LayerTreeModel::paneAboutToBeDeleted(Pane *pane)
+{
+    std::cerr << "paneDeleted: " << pane << std::endl;
+    m_deletedPanes.insert(pane);
+    emit layoutChanged();
+}
+
+void
 LayerTreeModel::propertyContainerAdded(PropertyContainer *)
 {
     emit layoutChanged();
@@ -80,6 +343,12 @@
 }
 
 void
+LayerTreeModel::paneLayerModelChanged()
+{
+    emit layoutChanged();
+}
+
+void
 LayerTreeModel::propertyContainerPropertyChanged(PropertyContainer *pc)
 {
     for (int i = 0; i < m_stack->getPaneCount(); ++i) {
@@ -88,9 +357,9 @@
         for (int j = 0; j < pane->getLayerCount(); ++j) {
             if (pane->getLayer(j) == pc) {
                 emit dataChanged(createIndex(pane->getLayerCount() - j - 1,
-                                             0, pane),
+                                             m_layerNameColumn, pane),
                                  createIndex(pane->getLayerCount() - j - 1,
-                                             3, pane));
+                                             m_modelNameColumn, pane));
             }
         }
     }
@@ -116,9 +385,9 @@
                           << params << "," << a << "): row " << pane->getLayerCount() - j - 1 << ", col " << 2 << std::endl;
 
                 emit dataChanged(createIndex(pane->getLayerCount() - j - 1,
-                                             2, pane),
+                                             m_layerPlayedColumn, pane),
                                  createIndex(pane->getLayerCount() - j - 1,
-                                             2, pane));
+                                             m_layerPlayedColumn, pane));
             }
         }
     }
@@ -148,7 +417,7 @@
     if (pane && pane->getLayerCount() > row) {
         Layer *layer = pane->getLayer(pane->getLayerCount() - row - 1);
         if (layer) {
-            if (col == 0) {
+            if (col == m_layerNameColumn) {
                 switch (role) {
                 case Qt::DisplayRole:
                     return QVariant(layer->objectName());
@@ -158,14 +427,14 @@
                                .arg(layer->getPropertyContainerIconName())));
                 default: break;
                 }
-            } else if (col == 1) {
+            } else if (col == m_layerVisibleColumn) {
                 if (role == Qt::CheckStateRole) {
                     return QVariant(layer->isLayerDormant(pane) ?
                                     Qt::Unchecked : Qt::Checked);
                 } else if (role == Qt::TextAlignmentRole) {
                     return QVariant(Qt::AlignHCenter);
                 }
-            } else if (col == 2) {
+            } else if (col == m_layerPlayedColumn) {
                 if (role == Qt::CheckStateRole) {
                     PlayParameters *params = layer->getPlayParameters();
                     if (params) return QVariant(params->isPlayMuted() ?
@@ -174,7 +443,7 @@
                 } else if (role == Qt::TextAlignmentRole) {
                     return QVariant(Qt::AlignHCenter);
                 }
-            } else if (col == 3) {
+            } else if (col == m_modelNameColumn) {
                 Model *model = layer->getModel();
                 if (model && role == Qt::DisplayRole) {
                     return QVariant(model->objectName());
@@ -200,13 +469,13 @@
     Layer *layer = pane->getLayer(pane->getLayerCount() - row - 1);
     if (!layer) return false;
 
-    if (col == 1) {
+    if (col == m_layerVisibleColumn) {
         if (role == Qt::CheckStateRole) {
             layer->showLayer(pane, value.toInt() == Qt::Checked);
             emit dataChanged(index, index);
             return true;
         }
-    } else if (col == 2) {
+    } else if (col == m_layerPlayedColumn) {
         if (role == Qt::CheckStateRole) {
             PlayParameters *params = layer->getPlayParameters();
             if (params) {
@@ -226,7 +495,8 @@
     Qt::ItemFlags flags = Qt::ItemIsEnabled;
     if (!index.isValid()) return flags;
 
-    if (index.column() == 1 || index.column() == 2) {
+    if (index.column() == m_layerVisibleColumn ||
+        index.column() == m_layerPlayedColumn) {
         flags |= Qt::ItemIsUserCheckable;
     } else if (index.column() == 0) {
         flags |= Qt::ItemIsSelectable;
@@ -241,10 +511,10 @@
 			   int role) const
 {
     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
-	if (section == 0) return QVariant(tr("Layer"));
-        else if (section == 1) return QVariant(tr("Shown"));
-        else if (section == 2) return QVariant(tr("Played"));
-	else if (section == 3) return QVariant(tr("Model"));
+	if (section == m_layerNameColumn) return QVariant(tr("Layer"));
+        else if (section == m_layerVisibleColumn) return QVariant(tr("Shown"));
+        else if (section == m_layerPlayedColumn) return QVariant(tr("Played"));
+	else if (section == m_modelNameColumn) return QVariant(tr("Model"));
     }
 
     return QVariant();
@@ -280,6 +550,11 @@
 {
     QObject *obj = static_cast<QObject *>(index.internalPointer());
 
+    if (m_deletedPanes.find(obj) != m_deletedPanes.end()) {
+//        m_deletedPanes.erase(obj);
+        return QModelIndex();
+    }
+
     Pane *pane = dynamic_cast<Pane *>(obj);
     if (pane) {
         int index = m_stack->getPaneIndex(pane);
@@ -308,10 +583,10 @@
 int
 LayerTreeModel::columnCount(const QModelIndex &parent) const
 {
-    if (!parent.isValid()) return 4;
+    if (!parent.isValid()) return m_columnCount;
 
     QObject *obj = static_cast<QObject *>(parent.internalPointer());
-    if (obj == m_stack) return 4; // row for a layer
+    if (obj == m_stack) return m_columnCount; // row for a layer
 
     return 1;
 }
--- a/widgets/LayerTree.h	Fri Nov 23 16:48:23 2007 +0000
+++ b/widgets/LayerTree.h	Wed Nov 28 17:45:37 2007 +0000
@@ -19,10 +19,62 @@
 
 #include <QAbstractItemModel>
 
+#include <set>
+
 class PaneStack;
 class View;
+class Pane;
 class Layer;
 class PropertyContainer;
+class Model;
+
+class ModelDataModel : public QAbstractItemModel
+{
+    Q_OBJECT
+
+public:
+    ModelDataModel(PaneStack *stack, bool waveModelsOnly, QObject *parent = 0);
+    virtual ~ModelDataModel();
+
+    QVariant data(const QModelIndex &index, int role) const;
+
+    bool setData(const QModelIndex &index, const QVariant &value, int role);
+
+    Qt::ItemFlags flags(const QModelIndex &index) const;
+
+    QVariant headerData(int section, Qt::Orientation orientation,
+                        int role = Qt::DisplayRole) const;
+
+    QModelIndex index(int row, int column,
+                      const QModelIndex &parent = QModelIndex()) const;
+
+    QModelIndex parent(const QModelIndex &index) const;
+
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+protected slots:
+    void paneAdded();
+    void paneDeleted();
+    void propertyContainerAdded(PropertyContainer *);
+    void propertyContainerRemoved(PropertyContainer *);
+    void propertyContainerSelected(PropertyContainer *);
+    void propertyContainerPropertyChanged(PropertyContainer *);
+    void playParametersAudibilityChanged(bool);
+    void paneLayerModelChanged();
+    void rebuildModelSet();
+
+protected:
+    PaneStack *m_stack;
+    bool m_waveModelsOnly;
+    int m_modelTypeColumn;
+    int m_modelNameColumn;
+    int m_modelMakerColumn;
+    int m_modelSourceColumn;
+    int m_columnCount;
+
+    std::set<Model *> m_models;
+};
 
 class LayerTreeModel : public QAbstractItemModel
 {
@@ -49,15 +101,24 @@
     int rowCount(const QModelIndex &parent = QModelIndex()) const;
     int columnCount(const QModelIndex &parent = QModelIndex()) const;
 
-protected:
-    PaneStack *m_stack;
-
 protected slots:
+    void paneAdded();
+    void paneAboutToBeDeleted(Pane *);
     void propertyContainerAdded(PropertyContainer *);
     void propertyContainerRemoved(PropertyContainer *);
     void propertyContainerSelected(PropertyContainer *);
     void propertyContainerPropertyChanged(PropertyContainer *);
+    void paneLayerModelChanged();
     void playParametersAudibilityChanged(bool);
+
+protected:
+    PaneStack *m_stack;
+    std::set<QObject *> m_deletedPanes;
+    int m_layerNameColumn;
+    int m_layerVisibleColumn;
+    int m_layerPlayedColumn;
+    int m_modelNameColumn;
+    int m_columnCount;
 };
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/LayerTreeDialog.cpp	Wed Nov 28 17:45:37 2007 +0000
@@ -0,0 +1,103 @@
+/* -*- 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 2007 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 "LayerTreeDialog.h"
+
+#include "LayerTree.h"
+#include "view/PaneStack.h"
+
+#include <QTreeView>
+#include <QTableView>
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QDialogButtonBox>
+#include <QHeaderView>
+#include <QApplication>
+#include <QDesktopWidget>
+
+LayerTreeDialog::LayerTreeDialog(PaneStack *stack, QWidget *parent) :
+    QDialog(parent),
+    m_paneStack(stack)
+{
+    setWindowTitle(tr("Layer Summary"));
+
+    QGridLayout *grid = new QGridLayout;
+    setLayout(grid);
+    
+    QGroupBox *modelBox = new QGroupBox;
+    modelBox->setTitle(tr("Audio Data Sources"));
+    grid->addWidget(modelBox, 0, 0);
+    grid->setRowStretch(0, 15);
+
+    QGridLayout *subgrid = new QGridLayout;
+    modelBox->setLayout(subgrid);
+
+    subgrid->setSpacing(0);
+    subgrid->setMargin(5);
+
+    m_modelView = new QTableView;
+    subgrid->addWidget(m_modelView);
+
+    m_modelView->verticalHeader()->hide();
+    m_modelView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
+    m_modelView->setShowGrid(false);
+
+    m_modelModel = new ModelDataModel(m_paneStack, true);
+    m_modelView->setModel(m_modelModel);
+
+    QGroupBox *layerBox = new QGroupBox;
+    layerBox->setTitle(tr("Panes and Layers"));
+    grid->addWidget(layerBox, 1, 0);
+    grid->setRowStretch(1, 20);
+
+    subgrid = new QGridLayout;
+    layerBox->setLayout(subgrid);
+
+    subgrid->setSpacing(0);
+    subgrid->setMargin(5);
+
+    m_layerView = new QTreeView;
+    m_layerView->header()->setResizeMode(QHeaderView::ResizeToContents);
+    subgrid->addWidget(m_layerView);
+
+    m_layerModel = new LayerTreeModel(m_paneStack);
+    m_layerView->setModel(m_layerModel);
+    m_layerView->expandAll();
+
+    QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Close);
+    connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
+    grid->addWidget(bb, 2, 0);
+    grid->setRowStretch(2, 0);
+    
+    QDesktopWidget *desktop = QApplication::desktop();
+    QRect available = desktop->availableGeometry();
+
+    int width = available.width() / 2;
+    int height = available.height() / 3;
+    if (height < 370) {
+        if (available.height() > 500) height = 370;
+    }
+    if (width < 500) {
+        if (available.width() > 650) width = 500;
+    }
+
+    resize(width, height);
+}
+
+LayerTreeDialog::~LayerTreeDialog()
+{
+    delete m_layerModel;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/LayerTreeDialog.h	Wed Nov 28 17:45:37 2007 +0000
@@ -0,0 +1,43 @@
+/* -*- 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 2007 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 _LAYER_TREE_DIALOG_H_
+#define _LAYER_TREE_DIALOG_H_
+
+#include <QDialog>
+
+class ModelDataModel;
+class LayerTreeModel;
+class PaneStack;
+class QTreeView;
+class QTableView;
+
+class LayerTreeDialog : public QDialog
+{
+    Q_OBJECT
+    
+public:
+    LayerTreeDialog(PaneStack *stack, QWidget *parent = 0);
+    ~LayerTreeDialog();
+
+protected:
+    PaneStack *m_paneStack;
+    ModelDataModel *m_modelModel;
+    QTableView *m_modelView;
+    LayerTreeModel *m_layerModel;
+    QTreeView *m_layerView;
+};
+
+#endif
--- a/widgets/PluginParameterDialog.cpp	Fri Nov 23 16:48:23 2007 +0000
+++ b/widgets/PluginParameterDialog.cpp	Wed Nov 28 17:45:37 2007 +0000
@@ -440,7 +440,8 @@
 }
 
 void
-PluginParameterDialog::setCandidateInputModels(const QStringList &models)
+PluginParameterDialog::setCandidateInputModels(const QStringList &models,
+                                               QString defaultModel)
 {
     m_inputModels->clear();
 
@@ -449,15 +450,17 @@
     QString lastModel = settings.value("lastinputmodel").toString();
     settings.endGroup();
 
+    if (defaultModel == "") defaultModel = lastModel;
+
     m_inputModels->show();
 
     m_inputModelList = models;
     m_inputModels->addItems(TextAbbrev::abbreviate(models, 80));
     m_inputModels->setCurrentIndex(0);
 
-    if (lastModel != "") {
+    if (defaultModel != "") {
         for (int i = 0; i < models.size(); ++i) {
-            if (lastModel == models[i]) {
+            if (defaultModel == models[i]) {
                 m_inputModels->setCurrentIndex(i);
                 m_currentInputModel = models[i];
                 break;
--- a/widgets/PluginParameterDialog.h	Fri Nov 23 16:48:23 2007 +0000
+++ b/widgets/PluginParameterDialog.h	Wed Nov 28 17:45:37 2007 +0000
@@ -54,7 +54,8 @@
     void setShowProcessingOptions(bool showWindowSize,
                                   bool showFrequencyDomainOptions);
 
-    void setCandidateInputModels(const QStringList &names);
+    void setCandidateInputModels(const QStringList &names,
+                                 QString defaultName);
     void setShowSelectionOnlyOption(bool show);
 
     Vamp::PluginBase *getPlugin() { return m_plugin; }
--- a/widgets/widgets.pro	Fri Nov 23 16:48:23 2007 +0000
+++ b/widgets/widgets.pro	Wed Nov 28 17:45:37 2007 +0000
@@ -23,6 +23,7 @@
            KeyReference.h \
            LabelCounterInputDialog.h \
            LayerTree.h \
+           LayerTreeDialog.h \
            LEDButton.h \
            ListInputDialog.h \
            NotifyingCheckBox.h \
@@ -49,6 +50,7 @@
            KeyReference.cpp \
            LabelCounterInputDialog.cpp \
            LayerTree.cpp \
+           LayerTreeDialog.cpp \
            LEDButton.cpp \
            ListInputDialog.cpp \
            NotifyingCheckBox.cpp \