365 lines
10 KiB
C++
365 lines
10 KiB
C++
|
// ATSModel class implementation
|
||
|
//
|
||
|
// The ATS document "model" (in the Qt 4 meaning)
|
||
|
//
|
||
|
// QATSH Copyright 2009 Jean-Philippe MEURET <jpmeuret@free.fr>
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
#include <QtCore/QModelIndex>
|
||
|
|
||
|
#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:
|
||
|
|
||
|
if (_pmiRootItem)
|
||
|
delete _pmiRootItem;
|
||
|
_pmiRootItem = new ATSRootItem(_pATSSound);
|
||
|
|
||
|
// Warn attached views and proxy models that the whole model has changed.
|
||
|
reset();
|
||
|
|
||
|
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<const ATSModelItem*>(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<const ATSPartialItem*>(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<const ATSResidualBandItem*>(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<const ATSModelItem*>(miIndex.internalPointer());
|
||
|
|
||
|
if (pmiItem)
|
||
|
{
|
||
|
switch (pmiItem->type())
|
||
|
{
|
||
|
case ATSModelItem::eFileProperties: // Row ignored, Column = property id
|
||
|
{
|
||
|
const ATSFilePropertiesItem *pmiPropsItem =
|
||
|
static_cast<const ATSFilePropertiesItem*>(pmiItem);
|
||
|
return pmiPropsItem->property((ATSFilePropertiesItem::ESoundPropertyId)miIndex.column());
|
||
|
}
|
||
|
|
||
|
case ATSModelItem::ePartial: // Row = frame, Column = property id
|
||
|
{
|
||
|
const ATSPartialItem *pmiPartItem =
|
||
|
static_cast<const ATSPartialItem*>(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<const ATSResidualBandItem*>(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<const ATSModelItem*>(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<const ATSPartialsItem*>(pmiParent);
|
||
|
return pmiParts->count();
|
||
|
}
|
||
|
|
||
|
case ATSModelItem::eResidualBands: // Column = residual band index
|
||
|
{
|
||
|
const ATSResidualBandsItem *pmiResids =
|
||
|
static_cast<const ATSResidualBandsItem*>(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<const ATSModelItem*>(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<const ATSPartialItem*>(pmiParent);
|
||
|
return pmiPart->nbFrames();
|
||
|
}
|
||
|
|
||
|
case ATSModelItem::eResidualBand: // Row = frame index (matrix: frame, property)
|
||
|
{
|
||
|
const ATSResidualBandItem *pmiResid =
|
||
|
static_cast<const ATSResidualBandItem*>(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<const ATSModelItem*>(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();
|
||
|
}
|