diff --git a/src/UI/DocumentViews/AssLinesModel.cc b/src/UI/DocumentViews/AssLinesModel.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d9a84a4378362d9effdf90946cd2f89602b8299d
--- /dev/null
+++ b/src/UI/DocumentViews/AssLinesModel.cc
@@ -0,0 +1,138 @@
+#include "AssLinesModel.hh"
+
+using namespace Vivy;
+
+quint64
+AssLinesModel::Item::getLineNumber() const noexcept
+{
+    return 0;
+}
+
+QString
+AssLinesModel::Item::getLineText() const noexcept
+{
+    QString ret;
+    if (auto ptr = line.lock()) {
+        for (const auto &syl : ptr->getContent()) {
+            ret.append(syl.getContent());
+            ret.append("|");
+        }
+    }
+    ret.remove(ret.size() - 1);
+    return ret;
+}
+
+QString
+AssLinesModel::Item::getLineStyle() const noexcept
+{
+    if (auto ptr = line.lock()) {
+        if (auto style = ptr->getStyle().lock()) {
+            return style->getElementName();
+        }
+    }
+    return "";
+}
+
+AssLinesModel::AssLinesModel(const QVector<Ass::LinePtr> &) noexcept
+{
+}
+
+AssLinesModel::~AssLinesModel() noexcept
+{
+    qDeleteAll(childs);
+}
+
+QVariant
+AssLinesModel::data(const QModelIndex &index, int role) const noexcept
+{
+    if (!index.isValid() || index.column() >= Utils::toUnderlying(Item::Field::TotalFieldCount))
+        return QVariant();
+
+    const Item *line = static_cast<const Item *>(index.internalPointer());
+
+    if (Qt::DisplayRole == role) {
+        switch (static_cast<Item::Field>(index.column())) {
+        case Item::Field::Line:
+            return QString("%1").arg(line->getLineNumber());
+
+        case Item::Field::Style:
+            return line->getLineStyle();
+
+        case Item::Field::Text:
+            return line->getLineText();
+
+        // We want a warning when adding a field so don"t use "default"
+        case Item::Field::TotalFieldCount:
+            qFatal("Unreachable");
+        }
+    }
+
+    // Happily ignore the edit role for now
+    else if (Qt::EditRole == role) {
+    }
+
+    return QVariant();
+}
+
+bool
+AssLinesModel::setData(const QModelIndex &index, const QVariant & /* value */, int role) noexcept
+{
+    const int col = index.column();
+    if (col >= Utils::toUnderlying(Item::Field::TotalFieldCount))
+        return false;
+
+    if (Qt::EditRole == role) {
+        emit dataChanged(index, index, { Qt::EditRole });
+        return true;
+    }
+
+    return false;
+}
+
+QVariant
+AssLinesModel::headerData(int section, Qt::Orientation oriantation, int role) const noexcept
+{
+    if (Qt::DisplayRole != role)
+        return QVariant();
+
+    else if (Qt::Horizontal == oriantation)
+        return headers.value(section);
+
+    else
+        return QVariant();
+}
+
+QModelIndex
+AssLinesModel::parent(const QModelIndex &) const noexcept
+{
+    return QModelIndex();
+}
+
+QModelIndex
+AssLinesModel::index(int row, int column, const QModelIndex &parent) const noexcept
+{
+    if (!hasIndex(row, column, parent))
+        return QModelIndex();
+    else if (row >= childs.size())
+        return QModelIndex();
+    else
+        return createIndex(row, column, childs[row]);
+}
+
+int
+AssLinesModel::rowCount(const QModelIndex & /* parent */) const noexcept
+{
+    return childs.size();
+}
+
+int
+AssLinesModel::columnCount(const QModelIndex & /* parent */) const noexcept
+{
+    return Utils::toUnderlying(Item::Field::TotalFieldCount);
+}
+
+Qt::ItemFlags
+AssLinesModel::flags(const QModelIndex &) const noexcept
+{
+    return Qt::ItemIsSelectable;
+}
diff --git a/src/UI/DocumentViews/AssLinesModel.hh b/src/UI/DocumentViews/AssLinesModel.hh
new file mode 100644
index 0000000000000000000000000000000000000000..1852aef1b53efe8d0cefe3aad2c55db138a36d1a
--- /dev/null
+++ b/src/UI/DocumentViews/AssLinesModel.hh
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "../../Lib/Utils.hh"
+#include "../../Lib/Ass/Ass.hh"
+#include <QAbstractItemModel>
+#include <QStringList>
+
+namespace Vivy
+{
+class AssLinesModel final : public QAbstractItemModel {
+    Q_OBJECT
+    VIVY_UNMOVABLE_OBJECT(AssLinesModel)
+
+private:
+    class Item final {
+        VIVY_UNMOVABLE_OBJECT(Item)
+
+    public:
+        Item(Ass::LineWeakPtr linePtr) noexcept;
+        ~Item() noexcept = default;
+
+        enum class Field : int {
+            Line  = 0,
+            Style = 1,
+            Text  = 2,
+
+            // Last, the count
+            TotalFieldCount,
+        };
+
+        quint64 getLineNumber() const noexcept;
+        QString getLineText() const noexcept;
+        QString getLineStyle() const noexcept;
+
+    private:
+        Ass::LineWeakPtr line;
+    };
+
+public:
+    explicit AssLinesModel(const QVector<Ass::LinePtr> &) noexcept;
+    ~AssLinesModel() noexcept;
+
+    QVariant data(const QModelIndex &, int role) const noexcept override;
+    bool setData(const QModelIndex &, const QVariant &v, int r = Qt::EditRole) noexcept override;
+
+    QVariant headerData(int section, Qt::Orientation, int r) const noexcept override;
+    QModelIndex parent(const QModelIndex &) const noexcept override;
+    QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const noexcept override;
+
+    int rowCount(const QModelIndex &parent = QModelIndex()) const noexcept override;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const noexcept override;
+
+    Qt::ItemFlags flags(const QModelIndex &) const noexcept override;
+
+private:
+    QStringList headers{ "N°", "Actor", "Text" };
+    QVector<Item *> childs;
+};
+}