diff --git a/GUI/Model/Data/MaskResultsPresenter.cpp b/GUI/Model/Data/MaskResultsPresenter.cpp
index c65c470bf3118339911513f5a20a8a38305583f6..ef8c7e2385769b8b45f55f49b65bb18513fd7d84 100644
--- a/GUI/Model/Data/MaskResultsPresenter.cpp
+++ b/GUI/Model/Data/MaskResultsPresenter.cpp
@@ -17,7 +17,7 @@
 #include "Device/Mask/IShape2D.h"
 #include "Device/Mask/MaskStack.h"
 #include "GUI/Model/Data/Data2DItem.h"
-#include "GUI/Model/Mask/MaskItems.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
 #include <QVBoxLayout>
 
 MaskResultsPresenter::MaskResultsPresenter(QWidget* parent)
diff --git a/GUI/Model/Data/ProjectionItems.h b/GUI/Model/Data/ProjectionItems.h
index d05948a729e71ce3c6730f65df4ec7605c458ce1..242922637913147776d36cca731634f1efd1983c 100644
--- a/GUI/Model/Data/ProjectionItems.h
+++ b/GUI/Model/Data/ProjectionItems.h
@@ -15,7 +15,7 @@
 #ifndef BORNAGAIN_GUI_MODEL_DATA_PROJECTIONITEMS_H
 #define BORNAGAIN_GUI_MODEL_DATA_PROJECTIONITEMS_H
 
-#include "GUI/Model/Mask/MaskItems.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
 #include "GUI/Support/Data/ID.h"
 
 //! A container to hold ProjectionItems, intended to store projections of color map on X, Y axes.
diff --git a/GUI/Model/Detector/DetectorItem.h b/GUI/Model/Detector/DetectorItem.h
index 038cd8e423b4154b66e0eac2c317f60f59497767..19c9bce6faaf99f2fc37b9ffcd67dc871e9e546d 100644
--- a/GUI/Model/Detector/DetectorItem.h
+++ b/GUI/Model/Detector/DetectorItem.h
@@ -17,7 +17,7 @@
 
 #include "GUI/Model/Descriptor/AxisProperty.h"
 #include "GUI/Model/Detector/ResolutionFunctionItemCatalog.h"
-#include "GUI/Model/Mask/MaskItems.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
 
 class Beam;
 class IDetector;
diff --git a/GUI/Model/Mask/MaskContainerItem.cpp b/GUI/Model/Mask/MaskContainerItem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7df2982bfd54ebc72ee6daa202cf1ba19d150933
--- /dev/null
+++ b/GUI/Model/Mask/MaskContainerItem.cpp
@@ -0,0 +1,170 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Model/Mask/MaskContainerItem.cpp
+//! @brief     Implements MaskItems classes
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#include "GUI/Model/Mask/MaskContainerItem.h"
+#include "GUI/Model/Mask/MaskContainerModel.h"
+#include "GUI/Support/XML/Backup.h"
+#include <QRegularExpression>
+
+namespace {
+namespace Tag {
+
+const QString Mask("Mask");
+
+} // namespace Tag
+} // namespace
+
+MaskContainerItem::MaskContainerItem()
+    : MaskItemObject()
+    , m_model(new MaskContainerModel(this))
+    , m_selectionModel(new QItemSelectionModel(m_model.get()))
+{
+}
+
+MaskContainerItem::~MaskContainerItem() = default;
+
+QVector<MaskItem*> MaskContainerItem::maskItems() const
+{
+    return m_maskItems.toQVector();
+}
+
+void MaskContainerItem::insertMask(int row, MaskItem* maskItem)
+{
+    // takes owning of maskItem!
+    m_maskItems.insert_at(row, maskItem);
+}
+
+void MaskContainerItem::addMaskItem(MaskItem* maskItem)
+{
+    // takes owning of maskItem!
+    m_maskItems.push_back(maskItem);
+}
+
+void MaskContainerItem::moveMask(int from_row, int to_row)
+{
+    m_maskItems.move(from_row, to_row);
+}
+
+void MaskContainerItem::removeMaskAt(int row)
+{
+    m_maskItems.delete_at(row);
+}
+
+void MaskContainerItem::removeMask(MaskItem* maskItem)
+{
+    m_maskItems.delete_element(maskItem);
+}
+
+RegionOfInterestItem* MaskContainerItem::regionOfInterestItem() const
+{
+    for (const auto& maskSel : m_maskItems)
+        if (auto* roi = dynamic_cast<RegionOfInterestItem*>(maskSel.currentItem()))
+            return roi;
+
+    return nullptr;
+}
+
+void MaskContainerItem::clear()
+{
+    m_maskItems.clear();
+}
+
+bool MaskContainerItem::isEmpty() const
+{
+    return m_maskItems.empty();
+}
+
+int MaskContainerItem::size() const
+{
+    return m_maskItems.size();
+}
+
+MaskItem* MaskContainerItem::at(const int idx)
+{
+    return m_maskItems.at(idx).currentItem();
+}
+
+int MaskContainerItem::indexOfItem(MaskItem* maskItem) const
+{
+    return m_maskItems.index_of(maskItem);
+}
+
+void MaskContainerItem::copyFrom(const MaskContainerItem* maskContainer)
+{
+    ASSERT(maskContainer);
+    GUI::Util::copyContents(maskContainer, this);
+}
+
+MaskContainerModel* MaskContainerItem::model()
+{
+    return m_model.get();
+}
+
+QItemSelectionModel* MaskContainerItem::selectionModel()
+{
+    return m_selectionModel.get();
+}
+
+void MaskContainerItem::updateMaskNames()
+{
+    const auto reg = QRegularExpression("[0-9]");
+
+    QMap<QString, int> numMasksByType;
+    for (size_t i = 0; i < m_maskItems.size(); i++) {
+
+        QString name = m_maskItems[i].currentItem()->maskName();
+        name.remove(reg);
+
+        int numMasks = 1;
+        if (numMasksByType.contains(name)) {
+            numMasks = numMasksByType.value(name) + 1;
+            numMasksByType.remove(name);
+        }
+        numMasksByType.insert(name, numMasks);
+        name += QString::number(numMasks);
+
+        m_maskItems[i].currentItem()->setMaskName(name);
+    }
+}
+
+void MaskContainerItem::writeTo(QXmlStreamWriter* w) const
+{
+    XML::writeAttribute(w, XML::Attrib::version, uint(1));
+
+    for (const auto& sel : m_maskItems) {
+        w->writeStartElement(Tag::Mask);
+        sel.writeTo(w);
+        w->writeEndElement();
+    }
+}
+
+void MaskContainerItem::readFrom(QXmlStreamReader* r, MessageService*)
+{
+    clear();
+
+    const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
+    Q_UNUSED(version)
+
+    while (r->readNextStartElement()) {
+        QString tag = r->name().toString();
+
+        if (tag == Tag::Mask) {
+            addMaskItem(nullptr);
+            m_maskItems.back().readFrom(r);
+            XML::gotoEndElementOfTag(r, tag);
+
+        } else
+            r->skipCurrentElement();
+    }
+}
diff --git a/GUI/Model/Mask/MaskContainerItem.h b/GUI/Model/Mask/MaskContainerItem.h
new file mode 100644
index 0000000000000000000000000000000000000000..89a12f4f798059e4a35f8bd347eb4c2d63d02822
--- /dev/null
+++ b/GUI/Model/Mask/MaskContainerItem.h
@@ -0,0 +1,88 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Model/Mask/MaskContainerItem.h
+//! @brief     Defines MaskItems classes
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#ifndef BORNAGAIN_GUI_MODEL_MASK_MASKCONTAINERITEM_H
+#define BORNAGAIN_GUI_MODEL_MASK_MASKCONTAINERITEM_H
+
+#include "GUI/Model/Mask/MaskItems.h"
+#include <QItemSelectionModel>
+
+class MaskContainerModel;
+
+//! Container holding various masks as children
+
+class MaskContainerItem : public MaskItemObject {
+public:
+    MaskContainerItem();
+    ~MaskContainerItem();
+
+    QVector<MaskItem*> maskItems() const;
+
+    //! Insert mask at given row.
+    virtual void insertMask(int row, MaskItem* maskItem);
+
+    virtual void addMaskItem(MaskItem* maskItem);
+
+    //! Move mask to a given row
+    virtual void moveMask(int from_row, int to_row);
+
+    //! Remove a given mask
+    virtual void removeMask(MaskItem* maskItem);
+
+    virtual void removeMaskAt(int row);
+
+    //! Can be nullptr.
+    RegionOfInterestItem* regionOfInterestItem() const;
+
+    //! Remove all masks
+    void clear();
+
+    //! Return true if the container has no MaskItems
+    bool isEmpty() const;
+
+    //! Return the number of MaskItems
+    int size() const;
+
+    //! Return the MaskItem at a given index
+    int indexOfItem(MaskItem* maskItem) const;
+
+    //! Return the index corresponding to a given MaskItem
+    MaskItem* at(const int idx);
+
+    //! Copy masks from another MaskContainerItem
+    void copyFrom(const MaskContainerItem* maskContainer);
+
+    //! Serialize/deserialize
+    void writeTo(QXmlStreamWriter* w) const;
+    void readFrom(QXmlStreamReader* r, MessageService* messageService = nullptr);
+
+    //! Return the corresponding MaskContainerModel
+    MaskContainerModel* model();
+
+    //! Return the corresponding QItemSelectionModel
+    QItemSelectionModel* selectionModel();
+
+    //! Update numbers in mask names
+    void updateMaskNames();
+
+public:
+    const QModelIndex rootIndex;
+
+protected:
+    SelectionVector<MaskItemCatalog> m_maskItems;
+    std::unique_ptr<MaskContainerModel> m_model;
+    std::unique_ptr<QItemSelectionModel> m_selectionModel;
+};
+
+#endif // BORNAGAIN_GUI_MODEL_MASK_MASKCONTAINERITEM_H
diff --git a/GUI/Model/Mask/MaskContainerModel.cpp b/GUI/Model/Mask/MaskContainerModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2c31ea97239127ee24afa659872815708a96b58e
--- /dev/null
+++ b/GUI/Model/Mask/MaskContainerModel.cpp
@@ -0,0 +1,127 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Model/Mask/MaskContainerModel.cpp
+//! @brief     Implements MaskItems classes
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#include "GUI/Model/Mask/MaskContainerModel.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
+#include "Base/Util/Assert.h"
+
+// Implementation of MaskContainerModel is based on the Qt source code for QStringListModel
+
+MaskContainerModel::MaskContainerModel(MaskContainerItem* container)
+    : maskContainer(container)
+{
+}
+
+MaskContainerModel::~MaskContainerModel() = default;
+
+// Begin overridden methods from QAbstractListModel
+
+int MaskContainerModel::rowCount(const QModelIndex& parent) const
+{
+    if (parent.isValid())
+        return 0;
+
+    return maskContainer->size();
+}
+
+QVariant MaskContainerModel::data(const QModelIndex& index, int role) const
+{
+    const qsizetype row = index.row();
+
+    if (row < 0 || row >= maskContainer->size())
+        return {};
+
+    if (role == Qt::DisplayRole || role == Qt::EditRole)
+        return {maskContainer->at(row)->maskName()};
+
+    return {};
+}
+
+// End overridden methods from QAbstractListModel
+
+void MaskContainerModel::insertMask(int row, MaskItem* maskItem)
+{
+    QAbstractListModel::beginInsertRows(maskContainer->rootIndex, row, row);
+    maskContainer->insertMask(row, maskItem);
+    QAbstractListModel::endInsertRows();
+}
+
+void MaskContainerModel::maskToModel(MaskItem* maskItem)
+{
+    qsizetype row = maskContainer->size() - 1;
+    QAbstractListModel::beginInsertRows(maskContainer->rootIndex, row, row);
+    maskContainer->addMaskItem(maskItem);
+    QAbstractListModel::endInsertRows();
+}
+
+
+//! Move mask to a given row
+void MaskContainerModel::moveMask(int from_row, int to_row)
+{
+    emit QAbstractListModel::beginMoveRows(maskContainer->rootIndex, from_row, from_row,
+                                           maskContainer->rootIndex, to_row);
+    maskContainer->moveMask(from_row, to_row);
+    emit QAbstractListModel::endMoveRows();
+}
+
+void MaskContainerModel::removeMaskAt(int row)
+{
+    QAbstractListModel::beginRemoveRows(maskContainer->rootIndex, row, row);
+    maskContainer->removeMaskAt(row);
+    QAbstractListModel::endRemoveRows();
+}
+
+void MaskContainerModel::removeMask(MaskItem* maskItem)
+{
+    const int row = maskContainer->indexOfItem(maskItem);
+    removeMaskAt(row);
+}
+
+RegionOfInterestItem* MaskContainerModel::regionOfInterestItem() const
+{
+    for (MaskItem* maskItem : maskContainer->maskItems())
+        if (auto* reg = dynamic_cast<RegionOfInterestItem*>(maskItem))
+            return reg;
+
+    return nullptr;
+}
+
+QModelIndex MaskContainerModel::indexOfItem(MaskItemObject* item) const
+{
+    const int row = maskContainer->indexOfItem(dynamic_cast<MaskItem*>(item));
+    return QAbstractListModel::index(row, 0, {});
+}
+
+MaskItem* MaskContainerModel::itemForIndex(const QModelIndex& index) const
+{
+    if (index.isValid())
+        return maskContainer->at(index.row());
+
+    return nullptr;
+}
+
+void MaskContainerModel::clear()
+{
+    QAbstractListModel::beginResetModel();
+    maskContainer->clear();
+    QAbstractListModel::endResetModel();
+}
+
+void MaskContainerModel::copy(const MaskContainerModel* src)
+{
+    clear();
+    if (src)
+        for (auto mask : src->maskContainer->maskItems())
+            maskToModel(mask);
+}
diff --git a/GUI/Model/Mask/MaskContainerModel.h b/GUI/Model/Mask/MaskContainerModel.h
new file mode 100644
index 0000000000000000000000000000000000000000..50c5b14d2f6b10865102d7399a8225802c4287c0
--- /dev/null
+++ b/GUI/Model/Mask/MaskContainerModel.h
@@ -0,0 +1,67 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Model/Mask/MaskContainerModel.h
+//! @brief     Defines MaskItems classes
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#ifndef BORNAGAIN_GUI_MODEL_MASK_MASKCONTAINERMODEL_H
+#define BORNAGAIN_GUI_MODEL_MASK_MASKCONTAINERMODEL_H
+
+#include <QAbstractListModel>
+
+class MaskContainerItem;
+class MaskItem;
+class MaskItemObject;
+class QModelIndex;
+class QVariant;
+class RegionOfInterestItem;
+
+//! Provides interfaces to a MaskContainerItem, allowing its contents to be displayed and modified
+//! using the Qt mechanisms.
+
+class MaskContainerModel : public QAbstractListModel {
+    Q_OBJECT
+public:
+    MaskContainerModel(MaskContainerItem* container);
+    ~MaskContainerModel();
+
+    //! Insert mask at given row.
+    void insertMask(int row, MaskItem* maskItem);
+
+    void maskToModel(MaskItem* maskItem);
+
+    //! Remove a given mask
+    void removeMask(MaskItem* maskItem);
+
+    //! Remove all masks
+    void clear();
+
+    //! Copy masks from another MaskContainerItem
+    void copy(const MaskContainerModel* src);
+
+    // Begin overridden methods from QAbstractListModel
+    QVariant data(const QModelIndex& index, int role) const override;
+    int rowCount(const QModelIndex& parent) const override;
+    // End overridden methods from QAbstractListModel
+
+    void moveMask(int from_row, int to_row);
+    void removeMaskAt(int row);
+
+    QModelIndex indexOfItem(MaskItemObject* item) const; // TODO: change this to MaskItem*
+    MaskItem* itemForIndex(const QModelIndex& index) const;
+
+    RegionOfInterestItem* regionOfInterestItem() const;
+
+public:
+    MaskContainerItem* maskContainer = nullptr;
+};
+
+#endif // BORNAGAIN_GUI_MODEL_MASK_MASKCONTAINERMODEL_H
diff --git a/GUI/Model/Mask/MaskItems.cpp b/GUI/Model/Mask/MaskItems.cpp
index 8fb1b0cc5cb43fc876bb121d45b91e31cca26e24..af456ff23ee2c1a589221fb91819a0b0e24b86de 100644
--- a/GUI/Model/Mask/MaskItems.cpp
+++ b/GUI/Model/Mask/MaskItems.cpp
@@ -18,6 +18,8 @@
 #include "Device/Mask/Line.h"
 #include "Device/Mask/Polygon.h"
 #include "Device/Mask/Rectangle.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
+#include "GUI/Model/Mask/MaskContainerModel.h"
 #include "GUI/Support/XML/Backup.h"
 #include <QRegularExpression>
 
@@ -46,149 +48,6 @@ const QString YUp("YUp");
 } // namespace Tag
 } // namespace
 
-MaskContainerItem::MaskContainerItem()
-    : MaskItemObject()
-    , m_model(new MaskContainerModel(this))
-    , m_selectionModel(new QItemSelectionModel(m_model.get()))
-{
-}
-
-QVector<MaskItem*> MaskContainerItem::maskItems() const
-{
-    return m_maskItems.toQVector();
-}
-
-void MaskContainerItem::insertMask(int row, MaskItem* maskItem)
-{
-    // takes owning of maskItem!
-    m_maskItems.insert_at(row, maskItem);
-}
-
-void MaskContainerItem::addMaskItem(MaskItem* maskItem)
-{
-    // takes owning of maskItem!
-    m_maskItems.push_back(maskItem);
-}
-
-void MaskContainerItem::moveMask(int from_row, int to_row)
-{
-    m_maskItems.move(from_row, to_row);
-}
-
-void MaskContainerItem::removeMaskAt(int row)
-{
-    m_maskItems.delete_at(row);
-}
-
-void MaskContainerItem::removeMask(MaskItem* maskItem)
-{
-    m_maskItems.delete_element(maskItem);
-}
-
-RegionOfInterestItem* MaskContainerItem::regionOfInterestItem() const
-{
-    for (const auto& maskSel : m_maskItems)
-        if (auto* roi = dynamic_cast<RegionOfInterestItem*>(maskSel.currentItem()))
-            return roi;
-
-    return nullptr;
-}
-
-void MaskContainerItem::clear()
-{
-    m_maskItems.clear();
-}
-
-bool MaskContainerItem::isEmpty() const
-{
-    return m_maskItems.empty();
-}
-
-int MaskContainerItem::size() const
-{
-    return m_maskItems.size();
-}
-
-MaskItem* MaskContainerItem::at(const int idx)
-{
-    return m_maskItems.at(idx).currentItem();
-}
-
-int MaskContainerItem::indexOfItem(MaskItem* maskItem) const
-{
-    return m_maskItems.index_of(maskItem);
-}
-
-void MaskContainerItem::copyFrom(const MaskContainerItem* maskContainer)
-{
-    ASSERT(maskContainer);
-    GUI::Util::copyContents(maskContainer, this);
-}
-
-MaskContainerModel* MaskContainerItem::model()
-{
-    return m_model.get();
-}
-
-QItemSelectionModel* MaskContainerItem::selectionModel()
-{
-    return m_selectionModel.get();
-}
-
-void MaskContainerItem::updateMaskNames()
-{
-    const auto reg = QRegularExpression("[0-9]");
-
-    QMap<QString, int> numMasksByType;
-    for (size_t i = 0; i < m_maskItems.size(); i++) {
-
-        QString name = m_maskItems[i].currentItem()->maskName();
-        name.remove(reg);
-
-        int numMasks = 1;
-        if (numMasksByType.contains(name)) {
-            numMasks = numMasksByType.value(name) + 1;
-            numMasksByType.remove(name);
-        }
-        numMasksByType.insert(name, numMasks);
-        name += QString::number(numMasks);
-
-        m_maskItems[i].currentItem()->setMaskName(name);
-    }
-}
-
-void MaskContainerItem::writeTo(QXmlStreamWriter* w) const
-{
-    XML::writeAttribute(w, XML::Attrib::version, uint(1));
-
-    for (const auto& sel : m_maskItems) {
-        w->writeStartElement(Tag::Mask);
-        sel.writeTo(w);
-        w->writeEndElement();
-    }
-}
-
-void MaskContainerItem::readFrom(QXmlStreamReader* r, MessageService*)
-{
-    clear();
-
-    const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
-    Q_UNUSED(version)
-
-    while (r->readNextStartElement()) {
-        QString tag = r->name().toString();
-
-        if (tag == Tag::Mask) {
-            addMaskItem(nullptr);
-            m_maskItems.back().readFrom(r);
-            XML::gotoEndElementOfTag(r, tag);
-
-        } else
-            r->skipCurrentElement();
-    }
-}
-
-/* ------------------------------------------------------------------------- */
 
 QString MaskItem::maskName() const
 {
@@ -866,114 +725,3 @@ MaskItemObject::~MaskItemObject()
 {
     emit maskToBeDestroyed(this);
 }
-/* ------------------------------------------------------------------------- */
-
-// Implementation of MaskContainerModel is based on the Qt source code for QStringListModel
-
-MaskContainerModel::MaskContainerModel(MaskContainerItem* container)
-    : maskContainer(container)
-{
-}
-
-MaskContainerModel::~MaskContainerModel() = default;
-
-// Begin overridden methods from QAbstractListModel
-
-int MaskContainerModel::rowCount(const QModelIndex& parent) const
-{
-    if (parent.isValid())
-        return 0;
-
-    return maskContainer->size();
-}
-
-QVariant MaskContainerModel::data(const QModelIndex& index, int role) const
-{
-    const qsizetype row = index.row();
-
-    if (row < 0 || row >= maskContainer->size())
-        return {};
-
-    if (role == Qt::DisplayRole || role == Qt::EditRole)
-        return {maskContainer->at(row)->maskName()};
-
-    return {};
-}
-
-// End overridden methods from QAbstractListModel
-
-void MaskContainerModel::insertMask(int row, MaskItem* maskItem)
-{
-    QAbstractListModel::beginInsertRows(maskContainer->rootIndex, row, row);
-    maskContainer->insertMask(row, maskItem);
-    QAbstractListModel::endInsertRows();
-}
-
-void MaskContainerModel::maskToModel(MaskItem* maskItem)
-{
-    qsizetype row = maskContainer->size() - 1;
-    QAbstractListModel::beginInsertRows(maskContainer->rootIndex, row, row);
-    maskContainer->addMaskItem(maskItem);
-    QAbstractListModel::endInsertRows();
-}
-
-
-//! Move mask to a given row
-void MaskContainerModel::moveMask(int from_row, int to_row)
-{
-    emit QAbstractListModel::beginMoveRows(maskContainer->rootIndex, from_row, from_row,
-                                           maskContainer->rootIndex, to_row);
-    maskContainer->moveMask(from_row, to_row);
-    emit QAbstractListModel::endMoveRows();
-}
-
-void MaskContainerModel::removeMaskAt(int row)
-{
-    QAbstractListModel::beginRemoveRows(maskContainer->rootIndex, row, row);
-    maskContainer->removeMaskAt(row);
-    QAbstractListModel::endRemoveRows();
-}
-
-void MaskContainerModel::removeMask(MaskItem* maskItem)
-{
-    const int row = maskContainer->indexOfItem(maskItem);
-    removeMaskAt(row);
-}
-
-RegionOfInterestItem* MaskContainerModel::regionOfInterestItem() const
-{
-    for (MaskItem* maskItem : maskContainer->maskItems())
-        if (auto* reg = dynamic_cast<RegionOfInterestItem*>(maskItem))
-            return reg;
-
-    return nullptr;
-}
-
-QModelIndex MaskContainerModel::indexOfItem(MaskItemObject* item) const
-{
-    const int row = maskContainer->indexOfItem(dynamic_cast<MaskItem*>(item));
-    return QAbstractListModel::index(row, 0, {});
-}
-
-MaskItem* MaskContainerModel::itemForIndex(const QModelIndex& index) const
-{
-    if (index.isValid())
-        return maskContainer->at(index.row());
-
-    return nullptr;
-}
-
-void MaskContainerModel::clear()
-{
-    QAbstractListModel::beginResetModel();
-    maskContainer->clear();
-    QAbstractListModel::endResetModel();
-}
-
-void MaskContainerModel::copy(const MaskContainerModel* src)
-{
-    clear();
-    if (src)
-        for (auto mask : src->maskContainer->maskItems())
-            maskToModel(mask);
-}
diff --git a/GUI/Model/Mask/MaskItems.h b/GUI/Model/Mask/MaskItems.h
index eec5f20fcd763100ef2d83887042a7e24906b821..478bcb5460aed2d532103d003588a2f95a6ed220 100644
--- a/GUI/Model/Mask/MaskItems.h
+++ b/GUI/Model/Mask/MaskItems.h
@@ -206,111 +206,4 @@ public:
     std::unique_ptr<IShape2D> createShape(double scale) const override;
 };
 
-
-class MaskContainerModel;
-
-//! Container holding various masks as children
-
-class MaskContainerItem : public MaskItemObject {
-public:
-    MaskContainerItem();
-
-    QVector<MaskItem*> maskItems() const;
-
-    //! Insert mask at given row.
-    virtual void insertMask(int row, MaskItem* maskItem);
-
-    virtual void addMaskItem(MaskItem* maskItem);
-
-    //! Move mask to a given row
-    virtual void moveMask(int from_row, int to_row);
-
-    //! Remove a given mask
-    virtual void removeMask(MaskItem* maskItem);
-
-    virtual void removeMaskAt(int row);
-
-    //! Can be nullptr.
-    RegionOfInterestItem* regionOfInterestItem() const;
-
-    //! Remove all masks
-    void clear();
-
-    //! Return true if the container has no MaskItems
-    bool isEmpty() const;
-
-    //! Return the number of MaskItems
-    int size() const;
-
-    //! Return the MaskItem at a given index
-    int indexOfItem(MaskItem* maskItem) const;
-
-    //! Return the index corresponding to a given MaskItem
-    MaskItem* at(const int idx);
-
-    //! Copy masks from another MaskContainerItem
-    void copyFrom(const MaskContainerItem* maskContainer);
-
-    //! Serialize/deserialize
-    void writeTo(QXmlStreamWriter* w) const;
-    void readFrom(QXmlStreamReader* r, MessageService* messageService = nullptr);
-
-    //! Return the corresponding MaskContainerModel
-    MaskContainerModel* model();
-
-    //! Return the corresponding QItemSelectionModel
-    QItemSelectionModel* selectionModel();
-
-    //! Update numbers in mask names
-    void updateMaskNames();
-
-public:
-    const QModelIndex rootIndex;
-
-protected:
-    SelectionVector<MaskItemCatalog> m_maskItems;
-    std::unique_ptr<MaskContainerModel> m_model;
-    std::unique_ptr<QItemSelectionModel> m_selectionModel;
-};
-
-//! Provides interfaces to a MaskContainerItem, allowing its contents to be displayed and modified
-//! using the Qt mechanisms.
-
-class MaskContainerModel : public QAbstractListModel {
-    Q_OBJECT
-public:
-    MaskContainerModel(MaskContainerItem* container);
-    ~MaskContainerModel();
-
-    //! Insert mask at given row.
-    void insertMask(int row, MaskItem* maskItem);
-
-    void maskToModel(MaskItem* maskItem);
-
-    //! Remove a given mask
-    void removeMask(MaskItem* maskItem);
-
-    //! Remove all masks
-    void clear();
-
-    //! Copy masks from another MaskContainerItem
-    void copy(const MaskContainerModel* src);
-
-    // Begin overridden methods from QAbstractListModel
-    QVariant data(const QModelIndex& index, int role) const override;
-    int rowCount(const QModelIndex& parent) const override;
-    // End overridden methods from QAbstractListModel
-
-    void moveMask(int from_row, int to_row);
-    void removeMaskAt(int row);
-
-    QModelIndex indexOfItem(MaskItemObject* item) const; // TODO: change this to MaskItem*
-    MaskItem* itemForIndex(const QModelIndex& index) const;
-
-    RegionOfInterestItem* regionOfInterestItem() const;
-
-public:
-    MaskContainerItem* maskContainer = nullptr;
-};
-
 #endif // BORNAGAIN_GUI_MODEL_MASK_MASKITEMS_H
diff --git a/GUI/View/Import/RealDataMaskWidget.cpp b/GUI/View/Import/RealDataMaskWidget.cpp
index b690736011bb449281c9afeb3c90cf5fdbb3b3b4..d3ed8ddd3b3c8277dbb07e0fd7d57cf411eff030 100644
--- a/GUI/View/Import/RealDataMaskWidget.cpp
+++ b/GUI/View/Import/RealDataMaskWidget.cpp
@@ -14,6 +14,7 @@
 
 #include "GUI/View/Import/RealDataMaskWidget.h"
 #include "GUI/Model/Data/Data2DItem.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
 #include "GUI/Model/Mask/MaskItems.h"
 #include "GUI/View/Mask/MaskEditorActions.h"
 #include "GUI/View/Mask/MaskEditorCanvas.h"
diff --git a/GUI/View/Mask/MaskEditorActions.cpp b/GUI/View/Mask/MaskEditorActions.cpp
index ad54ca2d8ae3a5908151d072036c967210087d2b..a68bfa95c5570bfbbd6c898de20f568dfdc84e07 100644
--- a/GUI/View/Mask/MaskEditorActions.cpp
+++ b/GUI/View/Mask/MaskEditorActions.cpp
@@ -13,6 +13,8 @@
 //  ************************************************************************************************
 
 #include "GUI/View/Mask/MaskEditorActions.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
+#include "GUI/Model/Mask/MaskContainerModel.h"
 #include "GUI/Model/Mask/MaskItems.h"
 #include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Support/Util/ActionFactory.h"
diff --git a/GUI/View/Mask/MaskEditorCanvas.cpp b/GUI/View/Mask/MaskEditorCanvas.cpp
index 48f79cf4b789fa5827311829aaa0015fb873fd05..d6a9c8a63bd6b6779d9b565766788ad1d1763d08 100644
--- a/GUI/View/Mask/MaskEditorCanvas.cpp
+++ b/GUI/View/Mask/MaskEditorCanvas.cpp
@@ -15,6 +15,7 @@
 #include "GUI/View/Mask/MaskEditorCanvas.h"
 #include "GUI/Model/Data/Data2DItem.h"
 #include "GUI/Model/Data/MaskResultsPresenter.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
 #include "GUI/Model/Mask/MaskItems.h"
 #include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/View/Mask/MaskGraphicsScene.h"
diff --git a/GUI/View/Mask/MaskEditorPropertyPanel.cpp b/GUI/View/Mask/MaskEditorPropertyPanel.cpp
index f63292d285409873f40572fc8f2ebed165f5c648..25eec0e75da8e0d06aa71e35bf6716c5b63928ec 100644
--- a/GUI/View/Mask/MaskEditorPropertyPanel.cpp
+++ b/GUI/View/Mask/MaskEditorPropertyPanel.cpp
@@ -14,6 +14,8 @@
 
 #include "GUI/View/Mask/MaskEditorPropertyPanel.h"
 #include "GUI/Model/Data/Data2DItem.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
+#include "GUI/Model/Mask/MaskContainerModel.h"
 #include "GUI/Model/Mask/MaskItems.h"
 #include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Support/Tool/LayoutUtil.h"
diff --git a/GUI/View/Mask/MaskGraphicsScene.cpp b/GUI/View/Mask/MaskGraphicsScene.cpp
index c1118cc98dcd8b50c55ee4846a88ec4868b6f038..7bc79523bca5ece41782dda46d69db9a73d7a856 100644
--- a/GUI/View/Mask/MaskGraphicsScene.cpp
+++ b/GUI/View/Mask/MaskGraphicsScene.cpp
@@ -14,6 +14,8 @@
 
 #include "GUI/View/Mask/MaskGraphicsScene.h"
 #include "GUI/Model/Data/Data2DItem.h"
+#include "GUI/Model/Mask/MaskContainerItem.h"
+#include "GUI/Model/Mask/MaskContainerModel.h"
 #include "GUI/Model/Mask/MaskItems.h"
 #include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/View/Mask/MaskGraphicsProxy.h"
diff --git a/GUI/View/Projection/ProjectionsEditorActions.cpp b/GUI/View/Projection/ProjectionsEditorActions.cpp
index faf8d3c3c98e2f641ace7e43f19fed236eb12fb5..bac97fd21bb9efd2441b983575eab1c38a321073 100644
--- a/GUI/View/Projection/ProjectionsEditorActions.cpp
+++ b/GUI/View/Projection/ProjectionsEditorActions.cpp
@@ -15,6 +15,7 @@
 #include "GUI/View/Projection/ProjectionsEditorActions.h"
 #include "GUI/Model/Data/Data2DItem.h"
 #include "GUI/Model/Data/ProjectionItems.h"
+#include "GUI/Model/Mask/MaskContainerModel.h"
 #include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/View/Projection/SaveProjectionsAssistant.h"
 #include <QAction>