diff --git a/toonz/sources/toonz/scenebrowserversioncontrol.cpp b/toonz/sources/toonz/scenebrowserversioncontrol.cpp
new file mode 100644
index 0000000..f21c892
--- /dev/null
+++ b/toonz/sources/toonz/scenebrowserversioncontrol.cpp
@@ -0,0 +1,594 @@
+
+
+#include "scenebrowser.h"
+#include "filebrowsermodel.h"
+#include "versioncontrolgui.h"
+#include "versioncontroltimeline.h"
+#include "fileselection.h"
+#include "dvdirtreeview.h"
+#include "tsystem.h"
+#include "tapp.h"
+
+#include "toonz/tscenehandle.h"
+#include "toonz/txshsimplelevel.h"
+#include "toonz/toonzscene.h"
+#include "toonz/levelset.h"
+#include "toonzqt/gutil.h"
+#include "toonzqt/icongenerator.h"
+
+namespace {
+//---------------------------------------------------------------------------
+
+QStringList getLevelFileNames(TFilePath path) {
+  TFilePath dir = path.getParentDir();
+  QDir qDir(QString::fromStdWString(dir.getWideString()));
+  QString levelName =
+      QRegExp::escape(QString::fromStdWString(path.getWideName()));
+  QString levelType = QString::fromStdString(path.getType());
+  QString exp(levelName + ".[0-9]{1,4}." + levelType);
+  QRegExp regExp(exp);
+  QStringList list = qDir.entryList(QDir::Files);
+  return list.filter(regExp);
+}
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+DvItemListModel::Status SceneBrowser::getItemVersionControlStatus(
+    const SceneBrowser::Item &item) {
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  return m_folderTreeView->getItemVersionControlStatus(node, item.m_path);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::setupVersionControlCommand(QString &file, QString &path) {
+  std::vector<TFilePath> filePaths;
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  fs->getSelectedFiles(filePaths);
+  if (filePaths.empty()) return;
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (!node) return;
+
+  DvDirVersionControlRootNode *rootNode = node->getVersionControlRootNode();
+
+  VersionControl *vc = VersionControl::instance();
+  if (rootNode) {
+    vc->setUserName(QString::fromStdWString(rootNode->getUserName()));
+    vc->setPassword(QString::fromStdWString(rootNode->getPassword()));
+  }
+
+  path = toQString(node->getPath());
+  file = toQString(filePaths[0].withoutParentDir());
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::setupVersionControlCommand(QStringList &files, QString &path,
+                                             int &sceneIconsCount) {
+  std::vector<TFilePath> filePaths;
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  fs->getSelectedFiles(filePaths);
+  if (filePaths.empty()) return;
+
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (!node) return;
+
+  int fileCount = filePaths.size();
+  for (int i = 0; i < fileCount; i++) {
+    TFilePath fp = filePaths[i];
+    if (fp.getDots() == "..") {
+      QStringList levelNames = getLevelFileNames(fp);
+
+      if (levelNames.isEmpty()) {
+        QString levelName =
+            QRegExp::escape(QString::fromStdWString(fp.getWideName()));
+        QString levelType = QString::fromStdString(fp.getType());
+        QString exp(levelName + ".[0-9]{1,4}." + levelType);
+        QRegExp regExp(exp);
+        levelNames = node->getMissingFiles(regExp);
+      }
+
+      int count = levelNames.size();
+      for (int i = 0; i < count; i++) files.append(levelNames.at(i));
+    } else {
+      QFileInfo fi(toQString(fp));
+      files.append(fi.fileName());
+    }
+
+    // Add also auxiliary files
+    if (fp.getDots() == ".." || fp.getType() == "tlv" ||
+        fp.getType() == "pli") {
+      TFilePathSet fpset;
+      TXshSimpleLevel::getFiles(fp, fpset);
+
+      TFilePathSet::iterator it;
+      for (it = fpset.begin(); it != fpset.end(); ++it)
+        files.append(QFileInfo(toQString(*it)).fileName());
+    }
+    // Add sceneIcon (only for scene files)
+    else if (fp.getType() == "tnz") {
+      TFilePath iconPath = ToonzScene::getIconPath(fp);
+      if (TFileStatus(iconPath).doesExist()) {
+        QDir dir(toQString(fp.getParentDir()));
+
+#ifdef MACOSX
+        files.append(dir.relativeFilePath(toQString(iconPath)));
+#else
+        files.append(
+            dir.relativeFilePath(toQString(iconPath)).replace("/", "\\"));
+#endif
+        sceneIconsCount++;
+      }
+    }
+  }
+
+  DvDirVersionControlRootNode *rootNode = node->getVersionControlRootNode();
+
+  if (rootNode) {
+    VersionControl *vc = VersionControl::instance();
+    vc->setUserName(QString::fromStdWString(rootNode->getUserName()));
+    vc->setPassword(QString::fromStdWString(rootNode->getPassword()));
+  }
+
+  path = toQString(node->getPath());
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::editVersionControl() {
+  QStringList files;
+  QString path;
+
+  int sceneIconsCount = 0;
+  setupVersionControlCommand(files, path, sceneIconsCount);
+  if (files.isEmpty() || path.isEmpty()) return;
+
+  VersionControl *vc = VersionControl::instance();
+
+  bool hasCurrentSceneFile = false;
+
+  // Check the scene file
+  TFilePath fp = TApp::instance()
+                     ->getCurrentScene()
+                     ->getScene()
+                     ->getScenePath()
+                     .withoutParentDir();
+  if (files.contains(toQString(fp))) hasCurrentSceneFile = true;
+
+  // Check the scene resource files
+  if (!hasCurrentSceneFile) {
+    QStringList currentSceneContents = vc->getCurrentSceneContents();
+    int fileSize                     = files.size();
+    for (int i = 0; i < fileSize; i++) {
+#ifdef MACOSX
+      QString fp = path + "/" + files.at(i);
+#else
+      QString fp = path + "\\" + files.at(i);
+#endif
+      if (currentSceneContents.contains(fp)) {
+        hasCurrentSceneFile = true;
+        break;
+      }
+    }
+  }
+
+  if (hasCurrentSceneFile) {
+    DVGui::warning(
+        tr("Some files that you want to edit are currently opened. Close them "
+           "first."));
+    return;
+  }
+
+  vc->lock(this, path, files, sceneIconsCount);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::editFrameRangeVersionControl() {
+  QString file;
+  QString path;
+  setupVersionControlCommand(file, path);
+  if (file.isEmpty() || path.isEmpty()) return;
+
+  TFilePath fp(TFilePath(path.toStdWString()) + file.toStdWString());
+  if (fp.getDots() == "..") {
+    QStringList list = getLevelFileNames(fp);
+    VersionControl::instance()->lockFrameRange(this, path, list);
+  } else {
+    const std::set<int> &indices = m_itemViewer->getSelectedIndices();
+    int frameCount =
+        m_itemViewer->getModel()
+            ->getItemData(*indices.begin(), DvItemListModel::FrameCount)
+            .toInt();
+
+    VersionControl::instance()->lockFrameRange(this, path, file, frameCount);
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::unlockFrameRangeVersionControl() {
+  QString file;
+  QString path;
+  setupVersionControlCommand(file, path);
+  if (file.isEmpty() || path.isEmpty()) return;
+
+  TFilePath fp(TFilePath(path.toStdWString()) + file.toStdWString());
+  if (fp.getDots() == "..") {
+    QStringList list = getLevelFileNames(fp);
+    VersionControl::instance()->unlockFrameRange(this, path, list);
+  } else
+    VersionControl::instance()->unlockFrameRange(this, path, file);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::putFrameRangeVersionControl() {
+  QString file;
+  QString path;
+  setupVersionControlCommand(file, path);
+  if (file.isEmpty() || path.isEmpty()) return;
+
+  VersionControl::instance()->commitFrameRange(this, path, file);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::revertFrameRangeVersionControl() {
+  QString file;
+  QString path;
+  setupVersionControlCommand(file, path);
+  if (file.isEmpty() || path.isEmpty()) return;
+
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (!node) return;
+
+  TFilePath fp = TFilePath(path.toStdWString()) + file.toStdWString();
+  if (fp.getDots() != "..") {
+    SVNStatus s = node->getVersionControlStatus(file);
+
+    QString from     = QString::number(s.m_editFrom);
+    QString to       = QString::number(s.m_editTo);
+    QString userName = VersionControl::instance()->getUserName();
+    QString hostName = TSystem::getHostName();
+
+    TFilePath fp(s.m_path.toStdWString());
+    QString tempFileName = QString::fromStdWString(fp.getWideName()) + "_" +
+                           userName + "_" + hostName + "_" + from + "-" + to +
+                           "." + QString::fromStdString(fp.getType());
+
+    TFilePath fullPath = node->getPath() + tempFileName.toStdWString();
+
+    if (TFileStatus(fullPath).doesExist())
+      VersionControl::instance()->revertFrameRange(this, path, file,
+                                                   toQString(fullPath));
+  } else {
+    // Use the hook file, if exist, as a tempFileName
+    QString tempFile;
+
+    QDir dir(path);
+    dir.setNameFilters(QStringList("*.xml"));
+    QStringList list = dir.entryList(QDir::Files | QDir::Hidden);
+    int listCount    = list.size();
+
+    if (listCount > 0) {
+      QString prefix = QString::fromStdWString(fp.getWideName()) + "_" +
+                       VersionControl::instance()->getUserName() + "_" +
+                       TSystem::getHostName();
+
+      for (int i = 0; i < listCount; i++) {
+        QString str = list.at(i);
+        if (str.startsWith(prefix)) {
+          tempFile = str;
+          tempFile.remove("_hooks");
+          tempFile = path + "/" + tempFile;
+          break;
+        }
+      }
+    }
+    VersionControl::instance()->revertFrameRange(this, path, file, tempFile);
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::updateAndEditVersionControl() {
+  std::vector<TFilePath> filePaths;
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  fs->getSelectedFiles(filePaths);
+  if (filePaths.empty()) return;
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (!node) return;
+
+  QStringList files;
+  int sceneIconsCount = 0;
+
+  TFilePath fp = filePaths[0];
+  QFileInfo fi(toQString(fp));
+  if (fp.getDots() == "..") {
+    QStringList levelNames = getLevelFileNames(fp);
+    int count              = levelNames.size();
+    for (int i = 0; i < count; i++) files.append(levelNames.at(i));
+  } else
+    files.append(fi.fileName());
+
+  SVNStatus status    = node->getVersionControlStatus(fi.fileName());
+  int workingRevision = status.m_workingRevision.toInt();
+
+  // Add also auxiliary files
+  if (fp.getDots() == ".." || fp.getType() == "tlv" || fp.getType() == "pli") {
+    TFilePathSet fpset;
+    TXshSimpleLevel::getFiles(fp, fpset);
+
+    TFilePathSet::iterator it;
+    for (it = fpset.begin(); it != fpset.end(); ++it)
+      files.append(QFileInfo(toQString(*it)).fileName());
+  }
+  // Add sceneIcon (only for scene files)
+  else if (fp.getType() == "tnz") {
+    TFilePath iconPath = ToonzScene::getIconPath(fp);
+    if (TFileStatus(iconPath).doesExist()) {
+      QDir dir(toQString(fp.getParentDir()));
+
+#ifdef MACOSX
+      files.append(dir.relativeFilePath(toQString(iconPath)));
+#else
+      files.append(
+          dir.relativeFilePath(toQString(iconPath)).replace("/", "\\"));
+#endif
+      sceneIconsCount++;
+    }
+  }
+
+  DvDirVersionControlRootNode *rootNode = node->getVersionControlRootNode();
+
+  VersionControl *vc = VersionControl::instance();
+  if (rootNode) {
+    vc->setUserName(QString::fromStdWString(rootNode->getUserName()));
+    vc->setPassword(QString::fromStdWString(rootNode->getPassword()));
+  }
+
+  QString path = toQString(node->getPath());
+
+  vc->updateAndLock(this, path, files, workingRevision, sceneIconsCount);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::unlockVersionControl() {
+  QStringList files;
+  QString path;
+
+  int sceneIconsCount = 0;
+  setupVersionControlCommand(files, path, sceneIconsCount);
+  if (files.isEmpty() || path.isEmpty()) return;
+
+  VersionControl *vc = VersionControl::instance();
+
+  bool hasCurrentSceneFile = false;
+
+  // Check the scene file
+  TFilePath fp = TApp::instance()
+                     ->getCurrentScene()
+                     ->getScene()
+                     ->getScenePath()
+                     .withoutParentDir();
+  if (files.contains(toQString(fp))) hasCurrentSceneFile = true;
+
+  // Check the scene resource files
+  if (!hasCurrentSceneFile) {
+    QStringList currentSceneContents = vc->getCurrentSceneContents();
+    int fileSize                     = files.size();
+    for (int i = 0; i < fileSize; i++) {
+#ifdef MACOSX
+      QString fp = path + "/" + files.at(i);
+#else
+      QString fp = path + "\\" + files.at(i);
+#endif
+      if (currentSceneContents.contains(fp)) {
+        hasCurrentSceneFile = true;
+        break;
+      }
+    }
+  }
+
+  if (hasCurrentSceneFile) {
+    DVGui::warning(
+        tr("Some files that you want to unlock are currently opened. Close "
+           "them first."));
+    return;
+  }
+  vc->unlock(this, path, files, sceneIconsCount);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::putVersionControl() {
+  QStringList files;
+  QString path;
+
+  int sceneIconsCount = 0;
+  setupVersionControlCommand(files, path, sceneIconsCount);
+  if (files.isEmpty() || path.isEmpty()) return;
+  VersionControl::instance()->commit(this, path, files, false, sceneIconsCount);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::revertVersionControl() {
+  QStringList files;
+  QString path;
+
+  int sceneIconsCount = 0;
+  setupVersionControlCommand(files, path, sceneIconsCount);
+  if (files.isEmpty() || path.isEmpty()) return;
+  VersionControl::instance()->revert(this, path, files, false, sceneIconsCount);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::deleteVersionControl() {
+  QStringList files;
+  QString path;
+
+  int sceneIconsCount = 0;
+  setupVersionControlCommand(files, path, sceneIconsCount);
+  if (files.isEmpty() || path.isEmpty()) return;
+  VersionControl::instance()->deleteFiles(this, path, files, sceneIconsCount);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::getVersionControl() {
+  QStringList files;
+  QString path;
+
+  int sceneIconsCount = 0;
+  setupVersionControlCommand(files, path, sceneIconsCount);
+  if (files.isEmpty() || path.isEmpty()) return;
+  VersionControl::instance()->update(this, path, files, sceneIconsCount, false,
+                                     false, false);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::getRevisionVersionControl() {
+  QStringList files;
+  QString path;
+
+  int sceneIconsCount = 0;
+  setupVersionControlCommand(files, path, sceneIconsCount);
+  if (files.isEmpty() || path.isEmpty()) return;
+  VersionControl::instance()->update(this, path, files, sceneIconsCount, false,
+                                     true, false);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::getRevisionHistory() {
+  QString file;
+  QString path;
+  setupVersionControlCommand(file, path);
+  if (file.isEmpty() || path.isEmpty()) return;
+
+  QStringList files;
+  int iconAdded;
+  setupVersionControlCommand(files, path, iconAdded);
+
+  files.removeAt(files.indexOf(file));
+
+  SVNTimeline *timelineDialog = new SVNTimeline(this, path, file, files);
+  connect(timelineDialog, SIGNAL(commandDone(const QStringList &)), this,
+          SLOT(onVersionControlCommandDone(const QStringList &)));
+
+  timelineDialog->show();
+  timelineDialog->raise();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onVersionControlCommandDone(const QStringList &files) {
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (!node) return;
+
+  // Refresh the tree view and hence the version control status of each item
+  m_folderTreeView->refreshVersionControl(node);
+
+  // Get the current scene
+  ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+  std::vector<TXshLevel *> levels;
+  scene->getLevelSet()->listLevels(levels);
+  QMap<TFilePath, TXshLevel *> sceneLevelPaths;
+  for (int i = 0; i < levels.size(); i++)
+    sceneLevelPaths[scene->decodeFilePath(levels[i]->getPath())] = levels[i];
+
+  TLevelSet *levelSetToCheck = new TLevelSet;
+
+  for (int i = 0; i < files.size(); i++) {
+    TFilePath path = TFilePath(files.at(i).toStdWString());
+    if (!path.isAbsolute()) {
+      TFilePath tempPath = TFilePath(node->getPath()) + path;
+      if (!TFileStatus(path).doesExist()) {
+        DvDirVersionControlNode *parent =
+            dynamic_cast<DvDirVersionControlNode *>(node->getParent());
+        while (parent && !TFileStatus(tempPath).doesExist()) {
+          tempPath = TFilePath(node->getPath()) + path;
+          parent = dynamic_cast<DvDirVersionControlNode *>(parent->getParent());
+        }
+        path = tempPath;
+      }
+    }
+
+    if (!TFileStatus(path).doesExist()) continue;
+
+    // Invalidate icons
+    IconGenerator::instance()->invalidate(path);
+
+    // TODO: Scene checking (could be useful)
+
+    // Level check
+    if (!sceneLevelPaths.isEmpty() && sceneLevelPaths.contains(path)) {
+      TXshLevel *level    = sceneLevelPaths.value(path);
+      TXshSimpleLevel *sl = level->getSimpleLevel();
+      if (sl) {
+        levelSetToCheck->insertLevel(sl);
+        sl->updateReadOnly();
+      }
+    }
+  }
+
+  VersionControlManager::instance()->setFrameRange(levelSetToCheck, true);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::showLockInformation() {
+  std::vector<TFilePath> filePaths;
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  fs->getSelectedFiles(filePaths);
+  if (filePaths.empty()) return;
+
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (!node) return;
+
+  QFileInfo fi(toQString(filePaths[0]));
+  SVNStatus status = node->getVersionControlStatus(fi.fileName());
+
+  SVNLockInfoDialog *dialog = new SVNLockInfoDialog(this, status);
+  dialog->show();
+  dialog->raise();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::showFrameRangeLockInfo() {
+  QString file;
+  QString path;
+  setupVersionControlCommand(file, path);
+  if (file.isEmpty() || path.isEmpty()) return;
+
+  TFilePath fp(TFilePath(path.toStdWString()) + file.toStdWString());
+  if (fp.getDots() == "..") {
+    QStringList list = getLevelFileNames(fp);
+    VersionControl::instance()->showFrameRangeLockInfo(this, path, list);
+  } else
+    VersionControl::instance()->showFrameRangeLockInfo(this, path, file);
+}
+
+//-----------------------------------------------------------------------------