// ATSModel class implementation // // The ATS document "model" (in the Qt 4 meaning) // // QATSH Copyright 2009 Jean-Philippe MEURET #include #include #include "ATSModel.h" #include "ATSModelItems.h" #include "ATSSound.h" // Constructors / Destructor =============================================== ATSModel::ATSModel(QObject *parent) : QAbstractItemModel(parent), _pATSSound(0), _pmiRootItem(0) { } ATSModel::~ATSModel() { if (_pmiRootItem) { delete _pmiRootItem; _pmiRootItem = 0; } if (_pATSSound) delete _pATSSound; } // ATS sound accessors ====================================================== void ATSModel::setSound(ATSSound* pSound) { if (_pATSSound) delete _pATSSound; _pATSSound = pSound; if (_pATSSound) { reInitialize(); _pATSSound->dump("Analysed ", std::cout); } } ATSSound* ATSModel::sound() { return _pATSSound; } // Item model (re-)initialization ======================================= void ATSModel::reInitialize(EReInitType eReInitType) // Don't call before load() or setSound() { //std::cout << "ATSModel::reInitialize(" << eReInitType << ")" << std::endl; switch (eReInitType) { case eEverything: beginResetModel(); if (_pmiRootItem) delete _pmiRootItem; _pmiRootItem = new ATSRootItem(_pATSSound); // Warn attached views and proxy models that the whole model has changed. endResetModel(); break; case ePartialsListOnly: // Rebuild partials list. _pmiRootItem->resetPartials(); // Warn attached views/proxy models of the changes. const QModelIndex qmiPartials = index(1, 0, QModelIndex()); emit dataChanged(qmiPartials, qmiPartials); const QModelIndex qmiProps = index(0, 0, QModelIndex()); emit dataChanged(index(0, ATSFilePropertiesItem::eSoundPropNbPartials, qmiProps), index(0, ATSFilePropertiesItem::eSoundPropMaxPartialFrequency, qmiProps)); break; } } // Model load from .ats file ============================================= bool ATSModel::load(const QString& qsATSFileName) { if (_pATSSound) delete _pATSSound; _pATSSound = new ATSSound(); const bool bLoaded = _pATSSound->load(qsATSFileName.toStdString().c_str()); if (bLoaded) { reInitialize(); _pATSSound->dump("Loaded ", std::cout); } return bLoaded; } // Model store to .ats file ================================================ bool ATSModel::store(const QString& qsATSFileName) const { _pATSSound->dump("Storing ", std::cout); return _pATSSound->store(qsATSFileName.toStdString().c_str()); } // Direct accessors to the root item ======================================= ATSRootItem* ATSModel::rootItem() { return _pmiRootItem; } // QAbstractItemModel implementation ======================================= Qt::ItemFlags ATSModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QModelIndex ATSModel::index(int row, int column, const QModelIndex &miParent) const { // If parent is the root item if (!miParent.isValid()) { switch (row) // Column ignored (should always be 0 according to columnCount()). { // Row 0 = Sound Properties case 0: return createIndex(0, 0, _pmiRootItem->fileProperties()); // Row 1 = Partials case 1: return createIndex(1, 0, _pmiRootItem->partials()); // Row 2 = Residual (Noise) bands case 2: return createIndex(2, 0, _pmiRootItem->residualBands()); // Nothing else. default: return QModelIndex(); } } // If parent is not the root item const ATSModelItem *pmiParent = static_cast(miParent.internalPointer()); if (pmiParent) { switch (pmiParent->type()) { case ATSModelItem::eFileProperties: // Row ignored, Column = property id if (column >= 0 && column < ATSFilePropertiesItem::eSoundPropNumber) return createIndex(0, column, miParent.internalPointer()); else return QModelIndex(); case ATSModelItem::ePartials: // Row ignored, Column = partial index if (column >= 0 && column < _pmiRootItem->partials()->count()) return createIndex(0, column, _pmiRootItem->partials()->partial(column)); else return QModelIndex(); case ATSModelItem::eResidualBands:// Row ignored, Column = residual band index if (column >= 0 && column < _pmiRootItem->residualBands()->count()) return createIndex(0, column, _pmiRootItem->residualBands()->residualBand(column)); else return QModelIndex(); case ATSModelItem::ePartial: // Row = frame index, Column = property id { const ATSPartialItem *pmiPart = static_cast(pmiParent); if (row >= 0 && row < pmiPart->nbFrames() && column >= 0 && column < ATSPartialItem::nbProperties()) return createIndex(row, column, miParent.internalPointer()); else return QModelIndex(); } case ATSModelItem::eResidualBand: // Row = frame index, Column = property id { const ATSResidualBandItem *pmiResid = static_cast(pmiParent); if (row >= 0 && row < pmiResid->nbFrames() && column >= 0 && column < ATSResidualBandItem::nbProperties()) return createIndex(row, column, miParent.internalPointer()); else return QModelIndex(); } default: return QModelIndex(); } } return QModelIndex(); } QVariant ATSModel::data(const QModelIndex &miIndex, int role) const { if (!miIndex.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); const ATSModelItem *pmiItem = static_cast(miIndex.internalPointer()); if (pmiItem) { switch (pmiItem->type()) { case ATSModelItem::eFileProperties: // Row ignored, Column = property id { const ATSFilePropertiesItem *pmiPropsItem = static_cast(pmiItem); return pmiPropsItem->property((ATSFilePropertiesItem::ESoundPropertyId)miIndex.column()); } case ATSModelItem::ePartial: // Row = frame, Column = property id { const ATSPartialItem *pmiPartItem = static_cast(pmiItem); return pmiPartItem->property(miIndex.row(), (ATSPartialItem::EPropertyId)miIndex.column()); } case ATSModelItem::eResidualBand: // Row = 2 => Column = Frame index (frame energy) { const ATSResidualBandItem *pmiResidItem = static_cast(pmiItem); return pmiResidItem->property(miIndex.row(), (ATSResidualBandItem::EPropertyId)miIndex.column()); } default: return QVariant(); } } return QVariant(); } int ATSModel::columnCount(const QModelIndex &miParent) const { // If parent is the root item if (!miParent.isValid()) return 1; // If parent is not the root item const ATSModelItem *pmiParent = static_cast(miParent.internalPointer()); if (pmiParent) { switch (pmiParent->type()) { case ATSModelItem::eFileProperties: // Column = property id return ATSFilePropertiesItem::eSoundPropNumber; case ATSModelItem::ePartials: // Column = partial index { const ATSPartialsItem *pmiParts = static_cast(pmiParent); return pmiParts->count(); } case ATSModelItem::eResidualBands: // Column = residual band index { const ATSResidualBandsItem *pmiResids = static_cast(pmiParent); return pmiResids->count(); } case ATSModelItem::ePartial: // Column = property id return ATSPartialItem::nbProperties(); case ATSModelItem::eResidualBand: // Column = property id return ATSResidualBandItem::nbProperties(); default: return 0; } } return 0; } int ATSModel::rowCount(const QModelIndex &miParent) const { // If parent is the root item if (!miParent.isValid()) { return 2 + (_pmiRootItem->residualBands()->count() > 0 ? 1 : 0); } // If parent is not the root item const ATSModelItem *pmiParent = static_cast(miParent.internalPointer()); if (pmiParent) { switch (pmiParent->type()) { case ATSModelItem::eFileProperties: // Only 1 row (list of properties) return 1; case ATSModelItem::ePartials: // Only 1 row (list of partials) return 1; case ATSModelItem::eResidualBands: // Only 1 row (list of residual bands) return 1; case ATSModelItem::ePartial: // Row = frame index (matrix: frame, property) { const ATSPartialItem *pmiPart = static_cast(pmiParent); return pmiPart->nbFrames(); } case ATSModelItem::eResidualBand: // Row = frame index (matrix: frame, property) { const ATSResidualBandItem *pmiResid = static_cast(pmiParent); return pmiResid->nbFrames(); } default: return 0; } } return 0; } QModelIndex ATSModel::parent(const QModelIndex &miChild) const { // Note: MUST be implemented at least for QItemSelection::indexes() (undocumented). if (miChild.isValid() && miChild.internalPointer()) { const ATSModelItem *pmiChild = static_cast(miChild.internalPointer()); switch (pmiChild->type()) { case ATSModelItem::ePartial: return createIndex(1, 0, _pmiRootItem->partials()); case ATSModelItem::eResidualBand: return createIndex(2, 0, _pmiRootItem->residualBands()); default: return QModelIndex(); } } return QModelIndex(); }