diff --git a/src/UI/Utils.cc b/src/UI/Utils.cc
index 940f65e7e41b7e667c4f21485dfe566610c02646..531e05119df8a7d1a2022581f2bc75197ccc8334 100644
--- a/src/UI/Utils.cc
+++ b/src/UI/Utils.cc
@@ -9,3 +9,16 @@ Utils::setTransparentBackgroundForWidget(QWidget *const w) noexcept
     w->setAttribute(Qt::WA_TranslucentBackground);
     w->setAttribute(Qt::WA_TransparentForMouseEvents);
 }
+
+const QString Utils::untouchedTabIndicator = QStringLiteral("(*)");
+const QString Utils::unsavedTabIndicator   = QStringLiteral("(+)");
+
+void
+Utils::deleteInternalWidget(QDockWidget *const dock) noexcept
+{
+    QWidget *widget = dock->widget();
+    if (widget != nullptr) {
+        delete widget;
+        dock->setWidget(nullptr);
+    }
+}
diff --git a/src/UI/Utils.hh b/src/UI/Utils.hh
index 751f86cc65d598212cf0b17af757d96d9a725bea..e5b71db13c6228348c797ba619b9be074ceae86d 100644
--- a/src/UI/Utils.hh
+++ b/src/UI/Utils.hh
@@ -11,4 +11,7 @@ class QWidget;
 namespace Vivy::Utils
 {
 void setTransparentBackgroundForWidget(QWidget *const) noexcept;
+void deleteInternalWidget(QDockWidget *const) noexcept;
+extern const QString untouchedTabIndicator;
+extern const QString unsavedTabIndicator;
 }
diff --git a/src/UI/VivyDocumentView.cc b/src/UI/VivyDocumentView.cc
index df87483c241107d6dc88297b6e80344bfd844916..575871eaf02ee740a1c9bcc8d9f8a726351073d1 100644
--- a/src/UI/VivyDocumentView.cc
+++ b/src/UI/VivyDocumentView.cc
@@ -52,9 +52,9 @@ VivyDocumentView::getDocument() const noexcept
 QString
 VivyDocumentView::getDocumentTabName() const noexcept
 {
-    return QString::fromUtf8(
-               document->checkDocumentOption(VivyDocument::UntouchedByDefault) ? "(*) " : "") +
-           Utils::getBaseName(document->getName());
+    return document->checkDocumentOption(VivyDocument::UntouchedByDefault)
+               ? (Utils::untouchedTabIndicator + " ")
+               : QString::fromUtf8("") + Utils::getBaseName(document->getName());
 }
 
 QString
@@ -74,73 +74,70 @@ VivyDocumentView::getDocumentTabToolTip() const noexcept
 void
 VivyDocumentView::loadVideoView() noexcept
 {
-    if (document->checkDocumentCapabilities(VivyDocument::Capabilities::VideoAble)) {
-        if (!videoView) {
-            videoView = new UnclosableDockWidget("Video View", this);
-            videoView->setAllowedAreas(Qt::AllDockWidgetAreas);
-            videoView->setFeatures(allDockFeatures);
-            addDockWidget(Qt::BottomDockWidgetArea, videoView, Qt::Vertical);
-        }
-
-        // Kubat: because the dock is "closable", when closed the widget itself
-        // is not deleted, it will be hidden and the content will be deleted.
-        // TODO: Check if it works on more platforms.
-        videoView->setWidget(new VideoView(videoView));
-        qobject_cast<VideoView *>(videoView->widget())
-            ->loadFile(document->getVideoSubDocument()->getFilePath());
+    if (!document->checkDocumentCapabilities(VivyDocument::Capabilities::VideoAble))
+        return;
+
+    if (!videoView) {
+        videoView = new UnclosableDockWidget("Video View", this);
+        videoView->setAllowedAreas(Qt::AllDockWidgetAreas);
+        videoView->setFeatures(allDockFeatures);
+        addDockWidget(Qt::BottomDockWidgetArea, videoView, Qt::Vertical);
     }
+
+    Utils::deleteInternalWidget(videoView);
+    videoView->setWidget(new VideoView(videoView));
+    qobject_cast<VideoView *>(videoView->widget())
+        ->loadFile(document->getVideoSubDocument()->getFilePath());
 }
 
 void
 VivyDocumentView::loadAssView() noexcept
 {
-    if (document->checkDocumentCapabilities(VivyDocument::Capabilities::AssAble)) {
-        if (!assLines) {
-            assLines = new UnclosableDockWidget("ASS Lines", this);
-            assLines->setFeatures(onlyClosableDockFeatures);
-            assLines->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea |
-                                      Qt::BottomDockWidgetArea);
-            addDockWidget(Qt::BottomDockWidgetArea, assLines, Qt::Vertical);
-        }
-
-        assModel.reset(new AssLinesModel(document->getAssSubDocument()->getLines()));
-        assLines->setWidget(new AssLinesView(assModel.get(), assLines));
+    if (!document->checkDocumentCapabilities(VivyDocument::Capabilities::AssAble))
+        return;
+
+    if (!assLines) {
+        assLines = new UnclosableDockWidget("ASS Lines", this);
+        assLines->setFeatures(onlyClosableDockFeatures);
+        assLines->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea |
+                                  Qt::BottomDockWidgetArea);
+        addDockWidget(Qt::BottomDockWidgetArea, assLines, Qt::Vertical);
     }
+
+    assModel.reset(new AssLinesModel(document->getAssSubDocument()->getLines()));
+    Utils::deleteInternalWidget(assLines);
+    assLines->setWidget(new AssLinesView(assModel.get(), assLines));
 }
 
 void
 VivyDocumentView::loadAudioView() noexcept
 {
-    if (document->checkDocumentCapabilities(VivyDocument::AudioAble)) {
-        std::shared_ptr<AudioSubDocument> audioDocument = document->getAudioSubDocument();
-        qDebug() << "Create an audio vizualizer for the audio sub document"
-                 << audioDocument->getFilePath();
-
-        AudioContext::StreamPtr stream = audioDocument->getDefaultStream();
-        if (stream == nullptr) {
-            qCritical() << "Failed to get default audio stream";
-            return;
-        }
-
-        if (!visualizer) {
-            visualizer = new UnclosableDockWidget("Visualizer", this);
-            visualizer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
-            visualizer->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea |
-                                        Qt::BottomDockWidgetArea);
-            visualizer->setFeatures(onlyClosableDockFeatures);
-            addDockWidget(Qt::LeftDockWidgetArea, visualizer, Qt::Horizontal);
-        }
-
-        // Kubat: don't check, may throw an error but don't think we can
-        // recover from it.
-        AudioVisualizer *visualizerInner = new AudioVisualizer(stream, visualizer);
-        visualizer->setWidget(visualizerInner);
-        visualizer->layout()->setAlignment(visualizerInner, Qt::AlignTop);
+    if (!document->checkDocumentCapabilities(VivyDocument::AudioAble))
+        return;
+
+    std::shared_ptr<AudioSubDocument> audioDocument = document->getAudioSubDocument();
+    AudioContext::StreamPtr stream                  = audioDocument->getDefaultStream();
+
+    if (stream == nullptr) {
+        qCritical() << "Failed to get default audio stream";
+        return;
     }
 
-    else {
-        qDebug() << "The document" << document->getName() << "is not AudioAble";
+    if (!visualizer) {
+        visualizer = new UnclosableDockWidget("Visualizer", this);
+        visualizer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
+        visualizer->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea |
+                                    Qt::BottomDockWidgetArea);
+        visualizer->setFeatures(onlyClosableDockFeatures);
+        addDockWidget(Qt::LeftDockWidgetArea, visualizer, Qt::Horizontal);
     }
+
+    // Kubat: don't check, may throw an error but don't think we can
+    // recover from it.
+    AudioVisualizer *visualizerInner = new AudioVisualizer(stream, visualizer);
+    Utils::deleteInternalWidget(visualizer);
+    visualizer->setWidget(visualizerInner);
+    visualizer->layout()->setAlignment(visualizerInner, Qt::AlignTop);
 }
 
 void
@@ -150,6 +147,8 @@ VivyDocumentView::closeDocument() noexcept
              << document.use_count() << ")";
     vivyApp->documentStore.closeDocument(document->getUuid());
 
+    TODO(Force close all floating docks)
+
     // Kubat: the visualizer pointer should have been deleted by the
     // deleteAllContent() call if it was created.
     deleteAllContent();