Commits

Ivan Andrianov committed 893d1cb

Transcode model.

Comments (0)

Files changed (6)

pysrc/fftranscoder/ui/transcodemodel.py

 from fftranscoder import codecs
 
 class TranscodeModel(QtCore.QAbstractItemModel):
-    (FILE_NAME, CODEC_NAME, BIT_RATE, BYTES_PER_SAMPLE, SAMPLE_RATE,
-        CHANNEL_COUNT, ARTIST_NAME, ALBUM_NAME, TRACK_NAME, YEAR, TRACK_NUMBER,
-        COLUMN_COUNT) = range(12)
-    (NO, ERROR, OK) = range(3)
-    
     filesTranscoded = QtCore.pyqtSignal(int)
 
     def __init__(self, parent = None):
-        QtCore.QAbstractItemModel.__init__(self, parent)
-
         self._threadPool = QtCore.QThreadPool()
-        
-        self._initValues()
-
-    def index(self, row, column, parent = QtCore.QModelIndex()):
-        if parent == QtCore.QModelIndex():
-            return self.createIndex(row, column)
-        else:
-            return QtCore.QModelIndex()
-
-    def parent(self, index):
-        return QtCore.QModelIndex()
-
-    def rowCount(self, parent = QtCore.QModelIndex()):
-        if parent == QtCore.QModelIndex():
-            return len(self._fileNames)
-        else:
-            return 0
-
-    def columnCount(self, parent = QtCore.QModelIndex()):
-        if parent == QtCore.QModelIndex():
-            return TranscodeModel.COLUMN_COUNT
-        else:
-            return 0
-
-    def data(self, index, role = QtCore.Qt.DisplayRole):
-        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
-            if index.column() == TranscodeModel.FILE_NAME:
-                return self._fileNames[index.row()]
-            else:
-                streamInfo = self._streamInfos[index.row()]
-                tagBlock = self._tagBlocks[index.row()]
-
-                if streamInfo is not None:
-                    if index.column() == TranscodeModel.CODEC_NAME:
-                        return self._codecNames[index.row()]
-                    elif index.column() == TranscodeModel.BIT_RATE:
-                        bitRate = self._bitRates[index.row()]
-
-                        if bitRate > 0:
-                            return str(bitRate / 1000) + ' ' + \
-                                self.tr('kbit/s')
-                        else:
-                            return self.tr('Lossless')
-                    elif index.column() == TranscodeModel.BYTES_PER_SAMPLE:
-                        return streamInfo.bytesPerSample()
-                    elif index.column() == TranscodeModel.SAMPLE_RATE:
-                        return str(streamInfo.sampleRate() / 1000.0) + ' ' + \
-                            self.tr('kHz')
-                    elif index.column() == TranscodeModel.CHANNEL_COUNT:
-                        return streamInfo.channelCount()
-                    elif index.column() == TranscodeModel.ARTIST_NAME:
-                        return tagBlock.artistName()
-                    elif index.column() == TranscodeModel.ALBUM_NAME:
-                        return tagBlock.albumName()
-                    elif index.column() == TranscodeModel.TRACK_NAME:
-                        return tagBlock.trackName()
-                    elif index.column() == TranscodeModel.YEAR:
-                        return tagBlock.year()
-                    elif index.column() == TranscodeModel.TRACK_NUMBER:
-                        return tagBlock.trackNumber()
-                    else:
-                        return None
-                else:
-                    if index.column() == TranscodeModel.CODEC_NAME:
-                        return self.tr('Unsupported')
-                    else:
-                        return None
-        elif role == QtCore.Qt.BackgroundRole:
-            status = self._statuses[index.row()]
-            
-            if status == TranscodeModel.ERROR:
-                return QtGui.QBrush(QtCore.Qt.red)
-            elif status == TranscodeModel.OK:
-                return QtGui.QBrush(QtCore.Qt.green)
-            else:
-                return None
-        else:
-            return None
-
-    def headerData(self, section, orientation, role = QtCore.Qt.DisplayRole):
-        if orientation == QtCore.Qt.Horizontal and \
-           role == QtCore.Qt.DisplayRole:
-            if section == TranscodeModel.FILE_NAME:
-                return self.tr('File name')
-            elif section == TranscodeModel.CODEC_NAME:
-                return self.tr('Codec')
-            elif section == TranscodeModel.BIT_RATE:
-                return self.tr('Bit rate')
-            elif section == TranscodeModel.BYTES_PER_SAMPLE:
-                return self.tr('Bytes per sample')
-            elif section == TranscodeModel.SAMPLE_RATE:
-                return self.tr('Sample rate')
-            elif section == TranscodeModel.CHANNEL_COUNT:
-                return self.tr('Channels')
-            else:
-                return None
-        else:
-            return None
-
-    def flags(self, index):
-        f = QtCore.QAbstractItemModel.flags(self, index)
-
-        if index.column() == TranscodeModel.ARTIST_NAME or \
-                index.column() == TranscodeModel.ALBUM_NAME or \
-                index.column() == TranscodeModel.TRACK_NAME or \
-                index.column() == TranscodeModel.YEAR or \
-                index.column() == TranscodeModel.TRACK_NUMBER:
-            f |= QtCore.Qt.ItemIsEditable
-
-        return f
-
-    def setData(self, index, value, role = QtCore.Qt.EditRole):
-        if role == QtCore.Qt.EditRole:
-            status = self._statuses[index.row()]
-            
-            if status != TranscodeModel.NO:
-                return False
-
-            tagBlock = self._tagBlocks[index.row()]
-
-            if index.column() == TranscodeModel.ARTIST_NAME:
-                tagBlock.setArtistName(value)
-            elif index.column() == TranscodeModel.ALBUM_NAME:
-                tagBlock.setAlbumName(value)
-            elif index.column() == TranscodeModel.TRACK_NAME:
-                tagBlock.setTrackName(value)
-            elif index.column() == TranscodeModel.YEAR:
-                tagBlock.setYear(value)
-            elif index.column() == TranscodeModel.TRACK_NUMBER:
-                tagBlock.setTrackNumber(value)
-            else:
-                return False
-            
-            self.dataChanged.emit(
-                  self.index(index.row(), index.column(), QtCore.QModelIndex()),
-                  self.index(index.row(), index.column(), QtCore.QModelIndex()))
-            return True
-        else:
-            return False
 
     @property
     def statuses(self):
     def addFiles(self, fileNames):
         self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(),
                              self.rowCount() + len(fileNames))
-
         self._fileNames.extend(fileNames)
-
         for fileName in fileNames:
             decoder = codecs.DecoderFinder.findDecoder(fileName)
-
             if decoder is not None:
                 self._codecNames.append(decoder.codecName())
                 self._bitRates.append(decoder.bitRate())
                 self._streamInfos.append(None)
                 self._tagBlocks.append(None)
                 self._statuses.append(TranscodeModel.ERROR)
-
         self.endInsertRows()
 
     def clear(self):
 
     def transcode(self, encoderPlugin, quality = None):
         self._transcodedFileCount = 0
-
         for i in range(self.rowCount()):
             status = self._statuses[i]
-            
             if status != TranscodeModel.NO:
                 continue
-
             inputFileName = self._fileNames[i]
             tagBlock = self._tagBlocks[i]
-
             outputFileName = TranscodeModel._processFileName(inputFileName,
                      encoderPlugin.fileNameExtension())
-
             if quality is None:
                 quality = 0
-
             transcoder = codecs.Transcoder(inputFileName,
                    outputFileName, encoderPlugin, tagBlock, quality)
             transcoder.setAutoDelete(False)
         transcoder = self.sender()
         index = self._transcoders[transcoder]
         del self._transcoders[transcoder]
-        
         if ok:
             self._statuses[index] = TranscodeModel.OK
         else:
             self._statuses[index] = TranscodeModel.ERROR
         self.dataChanged.emit(self.index(index, 0), self.index(index, 5))
-
         self._transcodedFileCount += 1
         self.filesTranscoded.emit(self._transcodedFileCount)
 
         sections = fileName.split('.')[0:-1]
         sections.append(fileNameExtension)
         return '.'.join(sections)
-
-    def _initValues(self):
-        self._fileNames = []
-        self._codecNames = []
-        self._bitRates = []
-        self._streamInfos = []
-        self._tagBlocks = []
-        self._statuses = []
-        self._transcoders = {}

src/ui/CMakeLists.txt

 set(FFTRANSCODER_UI_SRCS_CXX
   encoderdialog.cpp
   global.cpp
+  metadata.cpp
+  transcodemodel.cpp
 )
 
 set(FFTRANSCODER_UI_SRCS_UI

src/ui/metadata.cpp

+/*
+ * Copyright (C) 2012 by Ivan Andrianov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "metadata.h"
+#include <QSharedData>
+
+namespace FFTranscoder
+{
+namespace Ui
+{
+
+class MetaData::Data : public QSharedData {
+public:
+    QString fileName;
+    QString codecName;
+    uint bitRate;
+    Codecs::StreamInfo streamInfo;
+    Codecs::TagBlock tagBlock;
+};
+
+MetaData::MetaData()
+    : d(new MetaData::Data())
+{
+    setBitRate(0);
+}
+
+MetaData::MetaData(const MetaData & other)
+    : d(other.d)
+{
+}
+
+MetaData & MetaData::operator=(const MetaData & other)
+{
+    d = other.d;
+    return *this;
+}
+
+MetaData::~MetaData()
+{
+}
+
+bool MetaData::isEmpty() const
+{
+    return d->fileName.isEmpty() && d->codecName.isEmpty() && d->bitRate == 0
+            && d->streamInfo.isEmpty() && d->tagBlock.isEmpty();
+}
+
+QString MetaData::fileName() const
+{
+    return d->fileName;
+}
+
+void MetaData::setFileName(QString fileName)
+{
+    d->fileName = fileName;
+}
+
+QString MetaData::codecName() const
+{
+    return d->codecName;
+}
+
+void MetaData::setCodecName(QString codecName)
+{
+    d->codecName = codecName;
+}
+
+uint MetaData::bitRate() const
+{
+    return d->bitRate;
+}
+
+void MetaData::setBitRate(uint bitRate)
+{
+    d->bitRate = bitRate;
+}
+
+const Codecs::StreamInfo & MetaData::streamInfo() const
+{
+    return d->streamInfo;
+}
+
+Codecs::StreamInfo & MetaData::streamInfo()
+{
+    return d->streamInfo;
+}
+
+const Codecs::TagBlock & MetaData::tagBlock() const
+{
+    return d->tagBlock;
+}
+
+Codecs::TagBlock & MetaData::tagBlock()
+{
+    return d->tagBlock;
+}
+
+}
+}

src/ui/metadata.h

+/*
+ * Copyright (C) 2012 by Ivan Andrianov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef FFTRANSCODER_UI_METADATA_H
+#define FFTRANSCODER_UI_METADATA_H
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qstring.h>
+
+#include <codecs/streaminfo.h>
+#include <codecs/tagblock.h>
+
+#include "global.h"
+
+namespace FFTranscoder
+{
+namespace Ui
+{
+
+class FFTRANSCODER_UI_API MetaData
+{
+public:
+    MetaData();
+    MetaData(const MetaData & other);
+    MetaData & operator=(const MetaData & other);
+    ~MetaData();
+
+    bool isEmpty() const;
+
+    QString fileName() const;
+    void setFileName(QString fileName);
+
+    QString codecName() const;
+    void setCodecName(QString codecName);
+
+    uint bitRate() const;
+    void setBitRate(uint bitRate);
+
+    const Codecs::StreamInfo & streamInfo() const;
+    Codecs::StreamInfo & streamInfo();
+
+    const Codecs::TagBlock & tagBlock() const;
+    Codecs::TagBlock & tagBlock();
+    
+private:
+    class Data;
+    QSharedDataPointer<Data> d;
+};
+
+}
+}
+
+#endif // FFTRANSCODER_UI_METADATA_H

src/ui/transcodemodel.cpp

+/*
+ * Copyright (C) 2012 by Ivan Andrianov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "transcodemodel.h"
+
+#include <QtCore/qhash.h>
+#include <QtCore/qset.h>
+#include <QtGui/qbrush.h>
+
+#include <codecs/streaminfo.h>
+#include <codecs/tagblock.h>
+
+namespace FFTranscoder
+{
+namespace Ui
+{
+
+class TranscodeModel::Private
+{
+public:
+    Private();
+    ~Private();
+
+    QVariant displayRoleData(const QModelIndex & index) const;
+    QVariant streamInfoData(const QModelIndex & index) const;
+    QVariant tagBlockData(const QModelIndex & index) const;
+    QVariant backgroundRoleData(const QModelIndex & index) const;
+    void adjustTagBlock(const QModelIndex & index, const QVariant & value);
+
+    void initColumnNames();
+    void initStreamInfoColumns();
+    void initTagBlockColumns();
+
+    QList<TranscodeModel::Status> statuses;
+    QList<MetaData> metaDatas;
+
+    QHash<int, QString> columnNames;
+    QSet<int> streamInfoColumns;
+    QSet<int> tagBlockColumns;
+};
+
+TranscodeModel::TranscodeModel(QObject * parent)
+    : QAbstractItemModel(parent), d(new Private())
+{
+}
+
+TranscodeModel::~TranscodeModel()
+{
+}
+
+QModelIndex TranscodeModel::index(int row, int column,
+         const QModelIndex & parent) const
+{
+    if(!parent.isValid())
+    {
+        return createIndex(row, column);
+    }
+    return QModelIndex();
+}
+
+QModelIndex TranscodeModel::parent(const QModelIndex & /* child */) const
+{
+    return QModelIndex();
+}
+
+int TranscodeModel::rowCount(const QModelIndex & parent) const
+{
+    if(!parent.isValid())
+    {
+        return d->metaDatas.size();
+    }
+    return 0;
+}
+
+int TranscodeModel::columnCount(const QModelIndex & parent) const
+{
+    if(!parent.isValid())
+    {
+        return COLUMN_COUNT;
+    }
+    return 0;
+}
+
+QVariant TranscodeModel::data(const QModelIndex & index, int role) const
+{
+    if(role == Qt::DisplayRole || role == Qt::EditRole)
+    {
+        return d->displayRoleData(index);
+    }
+    if(role == Qt::BackgroundRole)
+    {
+        return d->backgroundRoleData(index);
+    }
+    return QVariant();
+}
+
+QVariant TranscodeModel::headerData(int section,
+        Qt::Orientation orientation, int role) const
+{
+    if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
+    {
+        return d->columnNames[section];
+    }
+    return QVariant();
+}
+
+Qt::ItemFlags TranscodeModel::flags(const QModelIndex & index) const
+{
+    Qt::ItemFlags flags = QAbstractItemModel::flags(index);
+    if(d->statuses[index.row()] == NO &&
+            d->tagBlockColumns.contains(index.column()))
+    {
+        flags |= Qt::ItemIsEditable;
+    }
+    return flags;
+}
+
+bool TranscodeModel::setData(const QModelIndex & index,
+        const QVariant & value, int role)
+{
+    if(!(flags(index) & Qt::ItemIsEditable) || role != Qt::EditRole)
+    {
+        return false;
+    }
+    d->adjustTagBlock(index, value);
+    emit dataChanged(index, index);
+    return true;
+}
+
+MetaData TranscodeModel::getElement(int row) const
+{
+    return d->metaDatas[row];
+}
+
+void TranscodeModel::addElement(MetaData metaData)
+{
+    beginInsertRows(QModelIndex(), rowCount(), rowCount());
+    if(metaData.isEmpty())
+    {
+        d->statuses.append(ERROR);
+    }
+    else
+    {
+        d->statuses.append(NO);
+    }
+    d->metaDatas.append(metaData);
+    endInsertRows();
+}
+
+bool TranscodeModel::setStatus(int row, Status status)
+{
+    if(d->statuses[row] == NO)
+    {
+        d->statuses[row] = status;
+        emit dataChanged(this->index(row, 0),
+                this->index(row, columnCount() - 1));
+        return true;
+    }
+    return false;
+}
+
+void TranscodeModel::clear()
+{
+    beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
+    d->statuses.clear();
+    d->metaDatas.clear();
+    endRemoveRows();
+}
+
+TranscodeModel::Private::Private()
+{
+    initColumnNames();
+    initStreamInfoColumns();
+    initTagBlockColumns();
+}
+
+TranscodeModel::Private::~Private()
+{
+}
+
+QVariant TranscodeModel::Private::displayRoleData(
+        const QModelIndex & index) const
+{
+    MetaData metaData = metaDatas[index.row()];
+    int column = index.column();
+    if(column == TranscodeModel::FILE_NAME)
+    {
+        return metaData.fileName();
+    }
+    if(column == TranscodeModel::CODEC_NAME)
+    {
+        return metaData.codecName();
+    }
+    if(column == TranscodeModel::BIT_RATE)
+    {
+        int bitRate = metaData.bitRate();
+        if(bitRate > 0)
+        {
+            return QString::number(bitRate / 1000) + " " + trUtf8("kbit/s");
+        }
+        return trUtf8("Lossless");
+    }
+    if(streamInfoColumns.contains(column))
+    {
+        return streamInfoData(index);
+    }
+    if(tagBlockColumns.contains(column))
+    {
+        return tagBlockData(index);
+    }
+    return QVariant();
+}
+
+QVariant TranscodeModel::Private::streamInfoData(
+        const QModelIndex & index) const
+{
+    const Codecs::StreamInfo & streamInfo = metaDatas[index.row()].streamInfo();
+    int column = index.column();
+    if(column == TranscodeModel::BYTES_PER_SAMPLE)
+    {
+        return streamInfo.bytesPerSample();
+    }
+    if(column == TranscodeModel::SAMPLE_RATE)
+    {
+        return QString::number(streamInfo.sampleRate() / 1000.0)
+                + " " + trUtf8("kHz");
+    }
+    if(column == TranscodeModel::CHANNEL_COUNT)
+    {
+        return streamInfo.channelCount();
+    }
+    return QVariant();
+}
+
+QVariant TranscodeModel::Private::tagBlockData(
+        const QModelIndex & index) const
+{
+    const Codecs::TagBlock & tagBlock = metaDatas[index.row()].tagBlock();
+    int column = index.column();
+    if(column == TranscodeModel::ARTIST_NAME)
+    {
+        return tagBlock.artistName();
+    }
+    if(column == TranscodeModel::ALBUM_NAME)
+    {
+        return tagBlock.albumName();
+    }
+    if(column == TranscodeModel::TRACK_NAME)
+    {
+        return tagBlock.trackName();
+    }
+    if(column == TranscodeModel::YEAR)
+    {
+        return tagBlock.year();
+    }
+    if(column == TranscodeModel::TRACK_NUMBER)
+    {
+        return tagBlock.trackNumber();
+    }
+    return QVariant();
+}
+
+QVariant TranscodeModel::Private::backgroundRoleData(
+        const QModelIndex & index) const
+{
+    TranscodeModel::Status status = statuses[index.row()];
+    if(status == TranscodeModel::ERROR)
+    {
+        return QBrush(Qt::red);
+    }
+    if(status == TranscodeModel::OK)
+    {
+        return QBrush(Qt::green);
+    }
+    return QVariant();
+}
+
+void TranscodeModel::Private::adjustTagBlock(const QModelIndex & index,
+        const QVariant & value)
+{
+    Codecs::TagBlock & tagBlock = metaDatas[index.row()].tagBlock();
+    int column = index.column();
+    if(column == TranscodeModel::ARTIST_NAME)
+    {
+        tagBlock.setArtistName(value.toString());
+    }
+    else if(column == TranscodeModel::ALBUM_NAME)
+    {
+        tagBlock.setAlbumName(value.toString());
+    }
+    else if(column == TranscodeModel::TRACK_NAME)
+    {
+        tagBlock.setTrackName(value.toString());
+    }
+    else if(column == TranscodeModel::YEAR)
+    {
+        tagBlock.setYear(value.toInt());
+    }
+    else if(column == TranscodeModel::TRACK_NUMBER)
+    {
+        tagBlock.setTrackNumber(value.toInt());
+    }
+}
+
+void TranscodeModel::Private::initColumnNames()
+{
+    columnNames[TranscodeModel::FILE_NAME] = trUtf8("File name");
+    columnNames[TranscodeModel::CODEC_NAME] = trUtf8("Codec");
+    columnNames[TranscodeModel::BIT_RATE] = trUtf8("Bit rate");
+    columnNames[TranscodeModel::BYTES_PER_SAMPLE] = trUtf8("Bytes per sample");
+    columnNames[TranscodeModel::SAMPLE_RATE] = trUtf8("Sample rate");
+    columnNames[TranscodeModel::CHANNEL_COUNT] = trUtf8("Channels");
+}
+
+void TranscodeModel::Private::initStreamInfoColumns()
+{
+    streamInfoColumns << TranscodeModel::BYTES_PER_SAMPLE <<
+            TranscodeModel::SAMPLE_RATE << TranscodeModel::CHANNEL_COUNT;
+}
+
+void TranscodeModel::Private::initTagBlockColumns()
+{
+    tagBlockColumns << TranscodeModel::ARTIST_NAME <<
+            TranscodeModel::ALBUM_NAME << TranscodeModel::TRACK_NAME <<
+            TranscodeModel::YEAR << TranscodeModel::TRACK_NUMBER;
+}
+
+}
+}

src/ui/transcodemodel.h

+/*
+ * Copyright (C) 2012 by Ivan Andrianov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef FFTRANSCODER_UI_TRANSCODEMODEL_H
+#define FFTRANSCODER_UI_TRANSCODEMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qscopedpointer.h>
+
+#include "metadata.h"
+
+namespace FFTranscoder
+{
+namespace Ui
+{
+
+class FFTRANSCODER_UI_API TranscodeModel : public QAbstractItemModel
+{
+    Q_OBJECT
+
+public:
+    enum Column
+    {
+        FILE_NAME, CODEC_NAME, BIT_RATE, BYTES_PER_SAMPLE, SAMPLE_RATE,
+        CHANNEL_COUNT, ARTIST_NAME, ALBUM_NAME, TRACK_NAME, YEAR, TRACK_NUMBER,
+        COLUMN_COUNT
+    };
+
+    enum Status
+    {
+        NO, ERROR, OK
+    };
+
+    TranscodeModel(QObject * parent = 0);
+    virtual ~TranscodeModel();
+
+    virtual QModelIndex index(int row, int column,
+            const QModelIndex & parent = QModelIndex()) const;
+    virtual QModelIndex parent(const QModelIndex & child) const;
+    virtual int rowCount(const QModelIndex & parent = QModelIndex()) const;
+    virtual int columnCount(const QModelIndex & parent = QModelIndex()) const;
+    virtual QVariant data(const QModelIndex & index,
+            int role = Qt::DisplayRole) const;
+    virtual QVariant headerData(int section, Qt::Orientation orientation,
+            int role = Qt::DisplayRole) const;
+    virtual Qt::ItemFlags flags(const QModelIndex & index) const;
+    virtual bool setData(const QModelIndex & index, const QVariant & value,
+            int role = Qt::EditRole);
+
+    MetaData getElement(int row) const;
+    void addElement(MetaData metaData);
+    bool setStatus(int row, Status status);
+    void clear();
+
+private:
+    class Private;
+    QScopedPointer<Private> d;
+};
+
+}
+}
+
+#endif // FFTRANSCODER_UI_TRANSCODEMODEL_H