Chris@43: Chris@58: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@43: Chris@43: /* Chris@59: Sonic Visualiser Chris@59: An audio file viewer and annotation editor. Chris@59: Centre for Digital Music, Queen Mary, University of London. Chris@59: This file copyright 2006 Chris Cannam. Chris@43: Chris@59: This program is free software; you can redistribute it and/or Chris@59: modify it under the terms of the GNU General Public License as Chris@59: published by the Free Software Foundation; either version 2 of the Chris@59: License, or (at your option) any later version. See the file Chris@59: COPYING included with this distribution for more information. Chris@43: */ Chris@43: Chris@43: #include "LayerTree.h" Chris@128: #include "view/PaneStack.h" Chris@43: Chris@298: #include "base/PlayParameters.h" Chris@128: #include "view/Pane.h" Chris@128: #include "layer/Layer.h" Chris@128: #include "data/model/Model.h" Chris@336: #include "data/model/WaveFileModel.h" Chris@43: Chris@280: #include Chris@43: #include Chris@43: Chris@43: Chris@392: ModelMetadataModel::ModelMetadataModel(PaneStack *stack, bool waveModelsOnly, Chris@336: QObject *parent) : Chris@43: QAbstractItemModel(parent), Chris@336: m_stack(stack), Chris@336: m_waveModelsOnly(waveModelsOnly) Chris@43: { Chris@336: if (m_waveModelsOnly) { Chris@336: m_modelTypeColumn = -1; Chris@336: m_modelNameColumn = 0; Chris@336: m_modelMakerColumn = 1; Chris@336: m_modelSourceColumn = 2; Chris@336: m_columnCount = 3; Chris@336: } else { Chris@336: m_modelTypeColumn = 0; Chris@336: m_modelNameColumn = 1; Chris@336: m_modelMakerColumn = 2; Chris@336: m_modelSourceColumn = 3; Chris@336: m_columnCount = 4; Chris@336: } Chris@336: Chris@336: connect(stack, SIGNAL(paneAdded()), this, SLOT(paneAdded())); Chris@336: connect(stack, SIGNAL(paneDeleted()), this, SLOT(paneDeleted())); Chris@298: Chris@298: for (int i = 0; i < stack->getPaneCount(); ++i) { Chris@298: Pane *pane = stack->getPane(i); Chris@298: if (!pane) continue; Chris@298: connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)), Chris@298: this, SLOT(propertyContainerAdded(PropertyContainer *))); Chris@298: connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)), Chris@298: this, SLOT(propertyContainerRemoved(PropertyContainer *))); Chris@298: connect(pane, SIGNAL(propertyContainerSelected(PropertyContainer *)), Chris@298: this, SLOT(propertyContainerSelected(PropertyContainer *))); Chris@298: connect(pane, SIGNAL(propertyContainerPropertyChanged(PropertyContainer *)), Chris@298: this, SLOT(propertyContainerPropertyChanged(PropertyContainer *))); Chris@298: connect(pane, SIGNAL(propertyContainerNameChanged(PropertyContainer *)), Chris@298: this, SLOT(propertyContainerPropertyChanged(PropertyContainer *))); Chris@336: connect(pane, SIGNAL(layerModelChanged()), Chris@336: this, SLOT(paneLayerModelChanged())); Chris@336: } Chris@336: Chris@336: rebuildModelSet(); Chris@336: } Chris@336: Chris@392: ModelMetadataModel::~ModelMetadataModel() Chris@336: { Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::rebuildModelSet() Chris@336: { Chris@336: std::set unfound = m_models; Chris@336: Chris@336: for (int i = 0; i < m_stack->getPaneCount(); ++i) { Chris@336: Chris@336: Pane *pane = m_stack->getPane(i); Chris@336: if (!pane) continue; Chris@336: Chris@336: for (int j = 0; j < pane->getLayerCount(); ++j) { Chris@336: Chris@336: Layer *layer = pane->getLayer(j); Chris@336: if (!layer) continue; Chris@336: Chris@336: Model *model = layer->getModel(); Chris@336: if (!model) continue; Chris@336: Chris@336: if (m_waveModelsOnly) { Chris@336: if (!dynamic_cast(model)) continue; Chris@336: } Chris@336: Chris@336: if (m_models.find(model) == m_models.end()) { Chris@336: connect(model, SIGNAL(aboutToBeDeleted()), Chris@336: this, SLOT(rebuildModelSet())); Chris@336: m_models.insert(model); Chris@336: } else { Chris@336: unfound.erase(model); Chris@336: } Chris@336: } Chris@336: } Chris@336: Chris@336: for (std::set::iterator i = unfound.begin(); Chris@336: i != unfound.end(); ++i) { Chris@336: m_models.erase(*i); Chris@336: } Chris@336: Chris@587: SVDEBUG << "ModelMetadataModel::rebuildModelSet: " << m_models.size() << " models" << endl; Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::paneAdded() Chris@336: { Chris@336: rebuildModelSet(); Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::paneDeleted() Chris@336: { Chris@336: rebuildModelSet(); Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::paneLayerModelChanged() Chris@336: { Chris@336: rebuildModelSet(); Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::propertyContainerAdded(PropertyContainer *) Chris@336: { Chris@336: rebuildModelSet(); Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::propertyContainerRemoved(PropertyContainer *) Chris@336: { Chris@336: rebuildModelSet(); Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::propertyContainerSelected(PropertyContainer *) Chris@336: { Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::propertyContainerPropertyChanged(PropertyContainer *pc) Chris@336: { Chris@336: } Chris@336: Chris@336: void Chris@392: ModelMetadataModel::playParametersAudibilityChanged(bool a) Chris@336: { Chris@336: } Chris@336: Chris@336: QVariant Chris@392: ModelMetadataModel::data(const QModelIndex &index, int role) const Chris@336: { Chris@336: if (!index.isValid()) return QVariant(); Chris@336: Chris@336: QObject *obj = static_cast(index.internalPointer()); Chris@336: int row = index.row(), col = index.column(); Chris@336: Chris@336: //!!! not exactly the ideal use of a std::set Chris@336: std::set::iterator itr = m_models.begin(); Chris@336: for (int i = 0; i < row && itr != m_models.end(); ++i, ++itr); Chris@336: if (itr == m_models.end()) return QVariant(); Chris@336: Chris@336: Model *model = *itr; Chris@336: Chris@336: if (role != Qt::DisplayRole) { Chris@336: if (m_waveModelsOnly && col == m_modelNameColumn && Chris@336: role == Qt::DecorationRole) { Chris@336: // There is no meaningful icon for a model, in general -- Chris@336: // the icons we have represent layer types and it would be Chris@336: // misleading to use them for models. However, if we're Chris@336: // only showing wave models, we use the waveform icon just Chris@336: // for decorative purposes. Chris@336: return QVariant(QIcon(QString(":/icons/waveform.png"))); Chris@336: } Chris@336: return QVariant(); Chris@336: } Chris@336: Chris@336: if (col == m_modelTypeColumn) { Chris@336: return QVariant(model->getTypeName()); Chris@336: } else if (col == m_modelNameColumn) { Chris@336: return QVariant(model->objectName()); Chris@336: } else if (col == m_modelMakerColumn) { Chris@336: return QVariant(model->getMaker()); Chris@336: } else if (col == m_modelSourceColumn) { Chris@336: return QVariant(model->getLocation()); Chris@336: } Chris@336: Chris@336: return QVariant(); Chris@336: } Chris@336: Chris@336: bool Chris@392: ModelMetadataModel::setData(const QModelIndex &index, const QVariant &value, int role) Chris@336: { Chris@336: return false; Chris@336: } Chris@336: Chris@336: Qt::ItemFlags Chris@392: ModelMetadataModel::flags(const QModelIndex &index) const Chris@336: { Chris@336: Qt::ItemFlags flags = Qt::ItemIsEnabled; Chris@336: return flags; Chris@336: } Chris@336: Chris@336: QVariant Chris@392: ModelMetadataModel::headerData(int section, Chris@336: Qt::Orientation orientation, Chris@336: int role) const Chris@336: { Chris@336: if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { Chris@336: if (section == m_modelTypeColumn) return QVariant(tr("Type")); Chris@336: else if (section == m_modelNameColumn) return QVariant(tr("Name")); Chris@336: else if (section == m_modelMakerColumn) return QVariant(tr("Maker")); Chris@336: else if (section == m_modelSourceColumn) return QVariant(tr("Source")); Chris@336: } Chris@336: Chris@336: return QVariant(); Chris@336: } Chris@336: Chris@336: QModelIndex Chris@392: ModelMetadataModel::index(int row, int column, const QModelIndex &parent) const Chris@336: { Chris@336: if (!parent.isValid()) { Chris@336: if (row >= m_models.size()) return QModelIndex(); Chris@336: return createIndex(row, column, 0); Chris@336: } Chris@336: Chris@336: return QModelIndex(); Chris@336: } Chris@336: Chris@336: QModelIndex Chris@392: ModelMetadataModel::parent(const QModelIndex &index) const Chris@336: { Chris@336: return QModelIndex(); Chris@336: } Chris@336: Chris@336: int Chris@392: ModelMetadataModel::rowCount(const QModelIndex &parent) const Chris@336: { Chris@336: if (!parent.isValid()) return m_models.size(); Chris@336: return 0; Chris@336: } Chris@336: Chris@336: int Chris@392: ModelMetadataModel::columnCount(const QModelIndex &parent) const Chris@336: { Chris@336: return m_columnCount; Chris@336: } Chris@336: Chris@336: Chris@336: Chris@336: LayerTreeModel::LayerTreeModel(PaneStack *stack, QObject *parent) : Chris@336: QAbstractItemModel(parent), Chris@336: m_stack(stack) Chris@336: { Chris@336: m_layerNameColumn = 0; Chris@336: m_layerVisibleColumn = 1; Chris@336: m_layerPlayedColumn = 2; Chris@336: m_modelNameColumn = 3; Chris@336: m_columnCount = 4; Chris@336: Chris@336: connect(stack, SIGNAL(paneAdded()), this, SLOT(paneAdded())); Chris@336: connect(stack, SIGNAL(paneAboutToBeDeleted(Pane *)), Chris@336: this, SLOT(paneAboutToBeDeleted(Pane *))); Chris@336: Chris@336: for (int i = 0; i < stack->getPaneCount(); ++i) { Chris@336: Pane *pane = stack->getPane(i); Chris@336: if (!pane) continue; Chris@336: connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)), Chris@336: this, SLOT(propertyContainerAdded(PropertyContainer *))); Chris@336: connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)), Chris@336: this, SLOT(propertyContainerRemoved(PropertyContainer *))); Chris@336: connect(pane, SIGNAL(propertyContainerSelected(PropertyContainer *)), Chris@336: this, SLOT(propertyContainerSelected(PropertyContainer *))); Chris@336: connect(pane, SIGNAL(propertyContainerPropertyChanged(PropertyContainer *)), Chris@336: this, SLOT(propertyContainerPropertyChanged(PropertyContainer *))); Chris@336: connect(pane, SIGNAL(propertyContainerNameChanged(PropertyContainer *)), Chris@336: this, SLOT(propertyContainerPropertyChanged(PropertyContainer *))); Chris@336: connect(pane, SIGNAL(layerModelChanged()), Chris@336: this, SLOT(paneLayerModelChanged())); Chris@336: Chris@298: for (int j = 0; j < pane->getLayerCount(); ++j) { Chris@298: Layer *layer = pane->getLayer(j); Chris@298: if (!layer) continue; Chris@298: PlayParameters *params = layer->getPlayParameters(); Chris@298: if (!params) continue; Chris@298: connect(params, SIGNAL(playAudibleChanged(bool)), Chris@298: this, SLOT(playParametersAudibilityChanged(bool))); Chris@298: } Chris@298: } Chris@43: } Chris@43: Chris@43: LayerTreeModel::~LayerTreeModel() Chris@43: { Chris@43: } Chris@43: Chris@298: void Chris@336: LayerTreeModel::paneAdded() Chris@336: { Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@336: LayerTreeModel::paneAboutToBeDeleted(Pane *pane) Chris@336: { Chris@336: std::cerr << "paneDeleted: " << pane << std::endl; Chris@336: m_deletedPanes.insert(pane); Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@298: LayerTreeModel::propertyContainerAdded(PropertyContainer *) Chris@298: { Chris@298: emit layoutChanged(); Chris@298: } Chris@298: Chris@298: void Chris@298: LayerTreeModel::propertyContainerRemoved(PropertyContainer *) Chris@298: { Chris@298: emit layoutChanged(); Chris@298: } Chris@298: Chris@298: void Chris@298: LayerTreeModel::propertyContainerSelected(PropertyContainer *) Chris@298: { Chris@298: emit layoutChanged(); Chris@298: } Chris@298: Chris@298: void Chris@336: LayerTreeModel::paneLayerModelChanged() Chris@336: { Chris@336: emit layoutChanged(); Chris@336: } Chris@336: Chris@336: void Chris@298: LayerTreeModel::propertyContainerPropertyChanged(PropertyContainer *pc) Chris@298: { Chris@298: for (int i = 0; i < m_stack->getPaneCount(); ++i) { Chris@298: Pane *pane = m_stack->getPane(i); Chris@298: if (!pane) continue; Chris@298: for (int j = 0; j < pane->getLayerCount(); ++j) { Chris@298: if (pane->getLayer(j) == pc) { Chris@298: emit dataChanged(createIndex(pane->getLayerCount() - j - 1, Chris@336: m_layerNameColumn, pane), Chris@298: createIndex(pane->getLayerCount() - j - 1, Chris@336: m_modelNameColumn, pane)); Chris@298: } Chris@298: } Chris@298: } Chris@298: } Chris@298: Chris@298: void Chris@298: LayerTreeModel::playParametersAudibilityChanged(bool a) Chris@298: { Chris@298: PlayParameters *params = dynamic_cast(sender()); Chris@298: if (!params) return; Chris@298: Chris@587: SVDEBUG << "LayerTreeModel::playParametersAudibilityChanged(" Chris@585: << params << "," << a << ")" << endl; Chris@298: Chris@298: for (int i = 0; i < m_stack->getPaneCount(); ++i) { Chris@298: Pane *pane = m_stack->getPane(i); Chris@298: if (!pane) continue; Chris@298: for (int j = 0; j < pane->getLayerCount(); ++j) { Chris@298: Layer *layer = pane->getLayer(j); Chris@298: if (!layer) continue; Chris@298: if (layer->getPlayParameters() == params) { Chris@587: SVDEBUG << "LayerTreeModel::playParametersAudibilityChanged(" Chris@585: << params << "," << a << "): row " << pane->getLayerCount() - j - 1 << ", col " << 2 << endl; Chris@298: Chris@298: emit dataChanged(createIndex(pane->getLayerCount() - j - 1, Chris@336: m_layerPlayedColumn, pane), Chris@298: createIndex(pane->getLayerCount() - j - 1, Chris@336: m_layerPlayedColumn, pane)); Chris@298: } Chris@298: } Chris@298: } Chris@298: } Chris@298: Chris@43: QVariant Chris@43: LayerTreeModel::data(const QModelIndex &index, int role) const Chris@43: { Chris@43: if (!index.isValid()) return QVariant(); Chris@56: Chris@43: QObject *obj = static_cast(index.internalPointer()); Chris@277: int row = index.row(), col = index.column(); Chris@277: Chris@277: Pane *pane = dynamic_cast(obj); Chris@277: if (!pane) { Chris@277: if (col == 0 && row < m_stack->getPaneCount()) { Chris@277: switch (role) { Chris@277: case Qt::DisplayRole: Chris@277: return QVariant(QString("Pane %1").arg(row + 1)); Chris@277: case Qt::DecorationRole: Chris@277: return QVariant(QIcon(QString(":/icons/pane.png"))); Chris@277: default: break; Chris@277: } Chris@277: } Chris@43: } Chris@43: Chris@277: if (pane && pane->getLayerCount() > row) { Chris@298: Layer *layer = pane->getLayer(pane->getLayerCount() - row - 1); Chris@277: if (layer) { Chris@336: if (col == m_layerNameColumn) { Chris@277: switch (role) { Chris@277: case Qt::DisplayRole: Chris@277: return QVariant(layer->objectName()); Chris@277: case Qt::DecorationRole: Chris@277: return QVariant Chris@277: (QIcon(QString(":/icons/%1.png") Chris@277: .arg(layer->getPropertyContainerIconName()))); Chris@277: default: break; Chris@277: } Chris@336: } else if (col == m_layerVisibleColumn) { Chris@298: if (role == Qt::CheckStateRole) { Chris@298: return QVariant(layer->isLayerDormant(pane) ? Chris@298: Qt::Unchecked : Qt::Checked); Chris@298: } else if (role == Qt::TextAlignmentRole) { Chris@298: return QVariant(Qt::AlignHCenter); Chris@298: } Chris@336: } else if (col == m_layerPlayedColumn) { Chris@298: if (role == Qt::CheckStateRole) { Chris@298: PlayParameters *params = layer->getPlayParameters(); Chris@298: if (params) return QVariant(params->isPlayMuted() ? Chris@298: Qt::Unchecked : Qt::Checked); Chris@298: else return QVariant(); Chris@298: } else if (role == Qt::TextAlignmentRole) { Chris@298: return QVariant(Qt::AlignHCenter); Chris@298: } Chris@336: } else if (col == m_modelNameColumn) { Chris@277: Model *model = layer->getModel(); Chris@277: if (model && role == Qt::DisplayRole) { Chris@277: return QVariant(model->objectName()); Chris@277: } Chris@277: } Chris@277: } Chris@43: } Chris@43: Chris@43: return QVariant(); Chris@43: } Chris@43: Chris@298: bool Chris@298: LayerTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) Chris@298: { Chris@298: if (!index.isValid()) return false; Chris@298: Chris@298: QObject *obj = static_cast(index.internalPointer()); Chris@298: int row = index.row(), col = index.column(); Chris@298: Chris@298: Pane *pane = dynamic_cast(obj); Chris@298: if (!pane || pane->getLayerCount() <= row) return false; Chris@298: Chris@298: Layer *layer = pane->getLayer(pane->getLayerCount() - row - 1); Chris@298: if (!layer) return false; Chris@298: Chris@336: if (col == m_layerVisibleColumn) { Chris@298: if (role == Qt::CheckStateRole) { Chris@298: layer->showLayer(pane, value.toInt() == Qt::Checked); Chris@298: emit dataChanged(index, index); Chris@298: return true; Chris@298: } Chris@336: } else if (col == m_layerPlayedColumn) { Chris@298: if (role == Qt::CheckStateRole) { Chris@298: PlayParameters *params = layer->getPlayParameters(); Chris@298: if (params) { Chris@298: params->setPlayMuted(value.toInt() == Qt::Unchecked); Chris@298: emit dataChanged(index, index); Chris@298: return true; Chris@298: } Chris@298: } Chris@298: } Chris@298: Chris@298: return false; Chris@298: } Chris@298: Chris@43: Qt::ItemFlags Chris@43: LayerTreeModel::flags(const QModelIndex &index) const Chris@43: { Chris@298: Qt::ItemFlags flags = Qt::ItemIsEnabled; Chris@298: if (!index.isValid()) return flags; Chris@298: Chris@336: if (index.column() == m_layerVisibleColumn || Chris@336: index.column() == m_layerPlayedColumn) { Chris@298: flags |= Qt::ItemIsUserCheckable; Chris@298: } else if (index.column() == 0) { Chris@298: flags |= Qt::ItemIsSelectable; Chris@298: } Chris@298: Chris@298: return flags; Chris@43: } Chris@43: Chris@43: QVariant Chris@56: LayerTreeModel::headerData(int section, Chris@43: Qt::Orientation orientation, Chris@43: int role) const Chris@43: { Chris@56: if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { Chris@336: if (section == m_layerNameColumn) return QVariant(tr("Layer")); Chris@336: else if (section == m_layerVisibleColumn) return QVariant(tr("Shown")); Chris@336: else if (section == m_layerPlayedColumn) return QVariant(tr("Played")); Chris@336: else if (section == m_modelNameColumn) return QVariant(tr("Model")); Chris@56: } Chris@56: Chris@56: return QVariant(); Chris@43: } Chris@43: Chris@43: QModelIndex Chris@43: LayerTreeModel::index(int row, int column, const QModelIndex &parent) const Chris@43: { Chris@277: // cell for a pane contains row, column, pane stack Chris@277: // -> its parent is the invalid cell Chris@277: Chris@277: // cell for a layer contains row, column, pane Chris@277: // -> its parent is row, column, pane stack (which identify the pane) Chris@43: Chris@43: if (!parent.isValid()) { Chris@277: if (row >= m_stack->getPaneCount() || column > 0) return QModelIndex(); Chris@43: return createIndex(row, column, m_stack); Chris@43: } Chris@43: Chris@43: QObject *obj = static_cast(parent.internalPointer()); Chris@277: Chris@277: if (obj == m_stack) { Chris@277: Pane *pane = m_stack->getPane(parent.row()); Chris@277: if (!pane || parent.column() > 0) return QModelIndex(); Chris@277: return createIndex(row, column, pane); Chris@43: } Chris@43: Chris@43: return QModelIndex(); Chris@43: } Chris@43: Chris@43: QModelIndex Chris@43: LayerTreeModel::parent(const QModelIndex &index) const Chris@43: { Chris@43: QObject *obj = static_cast(index.internalPointer()); Chris@43: Chris@336: if (m_deletedPanes.find(obj) != m_deletedPanes.end()) { Chris@336: // m_deletedPanes.erase(obj); Chris@336: return QModelIndex(); Chris@336: } Chris@336: Chris@43: Pane *pane = dynamic_cast(obj); Chris@43: if (pane) { Chris@277: int index = m_stack->getPaneIndex(pane); Chris@277: if (index >= 0) return createIndex(index, 0, m_stack); Chris@43: } Chris@43: Chris@43: return QModelIndex(); Chris@43: } Chris@43: Chris@43: int Chris@43: LayerTreeModel::rowCount(const QModelIndex &parent) const Chris@43: { Chris@277: if (!parent.isValid()) return m_stack->getPaneCount(); Chris@43: Chris@43: QObject *obj = static_cast(parent.internalPointer()); Chris@43: Chris@277: if (obj == m_stack) { Chris@277: Pane *pane = m_stack->getPane(parent.row()); Chris@277: if (!pane || parent.column() > 0) return 0; Chris@277: return pane->getLayerCount(); Chris@43: } Chris@43: Chris@43: return 0; Chris@43: } Chris@43: Chris@43: int Chris@43: LayerTreeModel::columnCount(const QModelIndex &parent) const Chris@43: { Chris@336: if (!parent.isValid()) return m_columnCount; Chris@43: Chris@43: QObject *obj = static_cast(parent.internalPointer()); Chris@336: if (obj == m_stack) return m_columnCount; // row for a layer Chris@56: Chris@43: return 1; Chris@43: } Chris@43: