diff --git a/toonz/sources/toonz/CMakeLists.txt b/toonz/sources/toonz/CMakeLists.txt
index c73aa8a..b468f19 100644
--- a/toonz/sources/toonz/CMakeLists.txt
+++ b/toonz/sources/toonz/CMakeLists.txt
@@ -82,6 +82,7 @@ set(MOC_HEADERS
     ruler.h
     savepresetpopup.h
     scanpopup.h
+    scenebrowser.h
     scenesettingspopup.h
     sceneviewer.h
     sceneviewercontextmenu.h
@@ -285,6 +286,8 @@ set(SOURCES
     runscriptcommand.cpp
     savepresetpopup.cpp
     scanpopup.cpp
+    scenebrowser.cpp
+    scenebrowserversioncontrol.cpp
     sceneviewercontextmenu.cpp
     scenesettingspopup.cpp
     scriptconsolepanel.cpp
diff --git a/toonz/sources/toonz/dvitemview.h b/toonz/sources/toonz/dvitemview.h
index 24be943..864afc5 100644
--- a/toonz/sources/toonz/dvitemview.h
+++ b/toonz/sources/toonz/dvitemview.h
@@ -255,6 +255,9 @@ public:
   }
   QColor getSelectedItemBackground() const { return m_selectedItemBackground; }
 
+  //exposed view parameters
+  void setIconSize(QSize size) { m_iconSize = size; }
+
 private:
   ViewType to_enum(int n) {
     switch (n) {
diff --git a/toonz/sources/toonz/filebrowser.cpp b/toonz/sources/toonz/filebrowser.cpp
index d1a0ef0..02a19e0 100644
--- a/toonz/sources/toonz/filebrowser.cpp
+++ b/toonz/sources/toonz/filebrowser.cpp
@@ -2351,7 +2351,7 @@ calculateTask:
 
 //-----------------------------------------------------------------------------
 
-inline void FrameCountReader::stopReading() { m_executor.cancelAll(); }
+void FrameCountReader::stopReading() { m_executor.cancelAll(); }
 
 //=============================================================================
 // FrameCountTask methods
diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp
index e522d3f..354ad65 100644
--- a/toonz/sources/toonz/mainwindow.cpp
+++ b/toonz/sources/toonz/mainwindow.cpp
@@ -2113,6 +2113,8 @@ void MainWindow::defineActions() {
 
   createMenuWindowsAction(MI_OpenFileBrowser, QT_TR_NOOP("&File Browser"), "",
                           "filebrowser");
+  createMenuWindowsAction(MI_OpenPreproductionBoard, QT_TR_NOOP("&Preproduction Board"), "",
+                          "scenebrowser");
   createMenuWindowsAction(MI_OpenFileViewer, QT_TR_NOOP("&Flipbook"), "",
                           "flipbook");
   createMenuWindowsAction(MI_OpenFunctionEditor, QT_TR_NOOP("&Function Editor"),
diff --git a/toonz/sources/toonz/menubar.cpp b/toonz/sources/toonz/menubar.cpp
index 2bbf9db..e39e898 100644
--- a/toonz/sources/toonz/menubar.cpp
+++ b/toonz/sources/toonz/menubar.cpp
@@ -420,6 +420,7 @@ QMenuBar *StackedMenuBar::createCleanupMenuBar() {
   //----Windows Menu
   QMenu *windowsMenu = addMenu(tr("Windows"), cleanupMenuBar);
   addMenuItem(windowsMenu, MI_OpenFileBrowser);
+  addMenuItem(windowsMenu, MI_OpenPreproductionBoard);
   addMenuItem(windowsMenu, MI_OpenStyleControl);
   addMenuItem(windowsMenu, MI_OpenComboViewer);
   addMenuItem(windowsMenu, MI_OpenXshView);
@@ -586,6 +587,7 @@ QMenuBar *StackedMenuBar::createPltEditMenuBar() {
   //---Windows Menu
   QMenu *windowsMenu = addMenu(tr("Windows"), pltEditMenuBar);
   addMenuItem(windowsMenu, MI_OpenFileBrowser);
+  addMenuItem(windowsMenu, MI_OpenPreproductionBoard);
   addMenuItem(windowsMenu, MI_OpenFileViewer);
   addMenuItem(windowsMenu, MI_OpenFilmStrip);
   addMenuItem(windowsMenu, MI_OpenPalette);
@@ -770,6 +772,7 @@ QMenuBar *StackedMenuBar::createInknPaintMenuBar() {
   addMenuItem(windowsMenu, MI_OpenTimelineView);
   addMenuItem(windowsMenu, MI_OpenColorModel);
   addMenuItem(windowsMenu, MI_OpenFileBrowser);
+  addMenuItem(windowsMenu, MI_OpenPreproductionBoard);
   addMenuItem(windowsMenu, MI_OpenFilmStrip);
   addMenuItem(windowsMenu, MI_OpenToolbar);
   addMenuItem(windowsMenu, MI_OpenToolOptionBar);
@@ -945,6 +948,7 @@ QMenuBar *StackedMenuBar::createXsheetMenuBar() {
   addMenuItem(windowsMenu, MI_OpenSchematic);
   addMenuItem(windowsMenu, MI_OpenComboViewer);
   addMenuItem(windowsMenu, MI_OpenFileBrowser);
+  addMenuItem(windowsMenu, MI_OpenPreproductionBoard);
   addMenuItem(windowsMenu, MI_OpenFunctionEditor);
   addMenuItem(windowsMenu, MI_OpenFileViewer);
   addMenuItem(windowsMenu, MI_OpenFilmStrip);
@@ -1010,6 +1014,7 @@ QMenuBar *StackedMenuBar::createBatchesMenuBar() {
   //----Windows Menu
   QMenu *windowsMenu = addMenu(tr("Windows"), batchesMenuBar);
   addMenuItem(windowsMenu, MI_OpenFileBrowser);
+  addMenuItem(windowsMenu, MI_OpenPreproductionBoard);
   addMenuItem(windowsMenu, MI_OpenBatchServers);
   addMenuItem(windowsMenu, MI_OpenTasks);
 
@@ -1415,6 +1420,7 @@ QMenuBar *StackedMenuBar::createFullMenuBar() {
   addMenuItem(windowsMenu, MI_OpenFilmStrip);
   windowsMenu->addSeparator();
   addMenuItem(windowsMenu, MI_OpenFileBrowser);
+  addMenuItem(windowsMenu, MI_OpenPreproductionBoard);
   addMenuItem(windowsMenu, MI_OpenFileBrowser2);
   windowsMenu->addSeparator();
   addMenuItem(windowsMenu, MI_OpenCleanupSettings);
diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h
index 11ee0b3..694a6ed 100644
--- a/toonz/sources/toonz/menubarcommandids.h
+++ b/toonz/sources/toonz/menubarcommandids.h
@@ -85,6 +85,7 @@
 
 // #define MI_OpenCurrentScene  "MI_OpenCurrentScene"
 #define MI_OpenFileBrowser "MI_OpenFileBrowser"
+#define MI_OpenPreproductionBoard "MI_OpenPreproductionBoard"
 #define MI_OpenFileViewer "MI_OpenFileViewer"
 #define MI_OpenFilmStrip "MI_OpenFilmStrip"
 #define MI_OpenPalette "MI_OpenPalette"
diff --git a/toonz/sources/toonz/scenebrowser.cpp b/toonz/sources/toonz/scenebrowser.cpp
new file mode 100644
index 0000000..bff45b0
--- /dev/null
+++ b/toonz/sources/toonz/scenebrowser.cpp
@@ -0,0 +1,2206 @@
+
+
+#include "scenebrowser.h"
+
+// Tnz6 includes
+#include "dvdirtreeview.h"
+#include "filebrowser.h"
+#include "filebrowsermodel.h"
+#include "fileselection.h"
+#include "filmstripselection.h"
+#include "castselection.h"
+#include "menubarcommandids.h"
+#include "floatingpanelcommand.h"
+#include "iocommand.h"
+#include "history.h"
+#include "tapp.h"
+
+// TnzQt includes
+#include "toonzqt/dvdialog.h"
+#include "toonzqt/icongenerator.h"
+#include "toonzqt/menubarcommand.h"
+#include "toonzqt/gutil.h"
+#include "toonzqt/trepetitionguard.h"
+
+// TnzLib includes
+#include "toonz/tscenehandle.h"
+#include "toonz/toonzscene.h"
+#include "toonz/txshsimplelevel.h"
+#include "toonz/txshsoundlevel.h"
+#include "toonz/tproject.h"
+#include "toonz/txshlevelhandle.h"
+#include "toonz/namebuilder.h"
+#include "toonz/toonzimageutils.h"
+#include "toonz/preferences.h"
+
+// TnzBase includes
+#include "tenv.h"
+
+// TnzCore includes
+#include "tsystem.h"
+#include "tconvert.h"
+#include "tfiletype.h"
+#include "tlevel_io.h"
+
+// Qt includes
+#include <QDrag>
+#include <QDragEnterEvent>
+#include <QDragMoveEvent>
+#include <QDropEvent>
+#include <QDragLeaveEvent>
+#include <QBoxLayout>
+#include <QLabel>
+#include <QByteArray>
+#include <QMenu>
+#include <QDateTime>
+#include <QInputDialog>
+#include <QDesktopServices>
+#include <QDirModel>
+#include <QDir>
+#include <QPixmap>
+#include <QUrl>
+#include <QRegExp>
+#include <QScrollBar>
+#include <QMap>
+#include <QPushButton>
+#include <QPalette>
+#include <QCheckBox>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QMessageBox>
+#include <QApplication>
+#include <QFormLayout>
+#include <QMainWindow>
+#include <QLineEdit>
+#include <QTreeWidgetItem>
+#include <QSplitter>
+#include <QFileSystemWatcher>
+
+// tcg includes
+#include "tcg/boost/range_utility.h"
+#include "tcg/boost/permuted_range.h"
+
+// boost includes
+#include <boost/bind.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/range/adaptor/filtered.hpp>
+#include <boost/range/adaptor/transformed.hpp>
+
+namespace ba = boost::adaptors;
+
+using namespace DVGui;
+
+
+//=============================================================================
+//      Local namespace
+//=============================================================================
+
+namespace {
+std::set<SceneBrowser *> activePreproductionBoards;
+//std::map<TFilePath, FCData> frameCountMap;
+//QMutex frameCountMapMutex;
+QMutex levelFileMutex;
+
+}  // namespace
+
+//=============================================================================
+//
+// SceneBrowserButtonBar
+//
+//-----------------------------------------------------------------------------
+
+SceneBrowserButtonBar::SceneBrowserButtonBar(DvItemViewer *itemViewer,
+                                             QWidget *parent)
+    : QToolBar(parent) {
+  setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+  setIconSize(QSize(17, 17));
+  setObjectName("buttonBar");
+  // buttonBar->setIconSize(QSize(10,10));
+
+  QIcon newFolderIcon = createQIcon("newfolder");
+  QAction *newScene  = new QAction(newFolderIcon, tr("Create new scene"), this);
+  newScene->setIconText(tr("Create scene"));
+  addAction(newScene);
+  //addSeparator();
+
+  connect(newScene, SIGNAL(triggered()), SIGNAL(newScene()));
+}
+
+//=============================================================================
+// SceneBrowser
+//-----------------------------------------------------------------------------
+
+#if QT_VERSION >= 0x050500
+SceneBrowser::SceneBrowser(QWidget *parent, Qt::WindowFlags flags,
+                         bool noContextMenu, bool multiSelectionEnabled)
+#else
+SceneBrowser::SceneBrowser(QWidget *parent, Qt::WFlags flags, bool noContextMenu,
+                         bool multiSelectionEnabled)
+#endif
+    : QFrame(parent), m_folderName(0), m_itemViewer(0) {
+  // style sheet
+  setObjectName("SceneBrowser");
+  setFrameStyle(QFrame::StyledPanel);
+
+  //m_mainSplitter      = new QSplitter(this);
+  m_folderTreeView    = new DvDirTreeView(this);
+  QFrame *box         = new QFrame(this);
+  QLabel *folderLabel = new QLabel(tr("Folder: "), this);
+  m_folderName        = new QLineEdit();
+  m_itemViewer = new DvItemViewer(box, noContextMenu, multiSelectionEnabled,
+                                  DvItemViewer::Browser);
+  DvItemViewerTitleBar *titleBar = new DvItemViewerTitleBar(m_itemViewer, box);
+  SceneBrowserButtonBar *buttonBar =
+      new SceneBrowserButtonBar(m_itemViewer, box);
+  DvItemViewerPanel *viewerPanel = m_itemViewer->getPanel();
+  viewerPanel->setThumbnailsView();
+  viewerPanel->setIconSize(QSize(192,108)); //default 80, 60
+  viewerPanel->addColumn(DvItemListModel::FileType, 50);
+  viewerPanel->addColumn(DvItemListModel::FrameCount, 50);
+  viewerPanel->addColumn(DvItemListModel::FileSize, 50);
+  viewerPanel->addColumn(DvItemListModel::CreationDate, 130);
+  viewerPanel->addColumn(DvItemListModel::ModifiedDate, 130);
+  if (Preferences::instance()->isSVNEnabled())
+    viewerPanel->addColumn(DvItemListModel::VersionControlStatus, 120);
+
+  viewerPanel->setSelection(new FileSelection());
+  DVItemViewPlayDelegate *itemViewPlayDelegate =
+      new DVItemViewPlayDelegate(viewerPanel);
+  viewerPanel->setItemViewPlayDelegate(itemViewPlayDelegate);
+
+  //m_mainSplitter->setObjectName("SceneBrowserSplitter");
+  m_folderTreeView->hide();
+  m_folderTreeView->setObjectName("DirTreeView");
+  box->setObjectName("castFrame");
+  box->setFrameStyle(QFrame::StyledPanel);
+
+  m_itemViewer->setModel(this);
+
+  // layout
+  QVBoxLayout *mainLayout = new QVBoxLayout();
+  mainLayout->setMargin(3);
+  mainLayout->setSpacing(2);
+  {
+    mainLayout->addWidget(buttonBar);
+
+    QHBoxLayout *folderLay = new QHBoxLayout();
+    folderLay->setMargin(0);
+    folderLay->setSpacing(0);
+    {
+      folderLay->addWidget(folderLabel, 0);
+      folderLay->addWidget(m_folderName, 1);
+    }
+    mainLayout->addLayout(folderLay, 0);
+
+    //m_mainSplitter->addWidget(m_folderTreeView);
+    QVBoxLayout *boxLayout = new QVBoxLayout(box);
+    boxLayout->setMargin(0);
+    boxLayout->setSpacing(0);
+    {
+      boxLayout->addWidget(titleBar, 0);
+      boxLayout->addWidget(m_itemViewer, 1);
+    }
+    //m_mainSplitter->addWidget(box);
+    mainLayout->addWidget(box, 1);
+  }
+  setLayout(mainLayout);
+
+  //m_mainSplitter->setSizes(QList<int>() << 270 << 500);
+
+  // signal-slot connections
+  bool ret = connect(m_folderTreeView, SIGNAL(currentNodeChanged()),
+                     itemViewPlayDelegate, SLOT(resetPlayWidget()));
+  // if the current forder is changed in the folder tree, then update in the
+  // item view
+  ret = ret && connect(m_folderTreeView, SIGNAL(currentNodeChanged()), this,
+                       SLOT(onTreeFolderChanged()));
+
+  ret = ret && connect(m_itemViewer, SIGNAL(clickedItem(int)), this,
+                       SLOT(onClickedItem(int)));
+  ret = ret && connect(m_itemViewer, SIGNAL(doubleClickedItem(int)), this,
+                       SLOT(onDoubleClickedItem(int)));
+  ret =
+      ret && connect(m_itemViewer, SIGNAL(selectedItems(const std::set<int> &)),
+                     this, SLOT(onSelectedItems(const std::set<int> &)));
+  ret = ret && connect(buttonBar, SIGNAL(newScene()), this, SLOT(newScene()));
+
+  ret = ret && connect(&m_frameCountReader, SIGNAL(calculatedFrameCount()),
+                       m_itemViewer->getPanel(), SLOT(update()));
+
+  QAction *refresh = CommandManager::instance()->getAction(MI_RefreshTree);
+  ret = ret && connect(refresh, SIGNAL(triggered()), this, SLOT(refresh()));
+  addAction(refresh);
+
+  // Version Control instance connection
+  if (Preferences::instance()->isSVNEnabled())
+    ret =
+        ret && connect(VersionControl::instance(),
+                       SIGNAL(commandDone(const QStringList &)), this,
+                       SLOT(onVersionControlCommandDone(const QStringList &)));
+
+  // if the folderName is edited, move the current folder accordingly
+  ret = ret && connect(m_folderName, SIGNAL(editingFinished()), this,
+                       SLOT(onFolderEdited()));
+
+  // folder history
+  ret = ret && connect(m_folderTreeView, SIGNAL(currentNodeChanged()), this,
+                       SLOT(storeFolderHistory()));
+
+  // check out the update of the current folder.
+  // Use MyFileSystemWatcher which is shared by all browsers.
+  // Adding and removing paths to the watcher is done in DvDirTreeView.
+  ret = ret && connect(MyFileSystemWatcher::instance(),
+                       SIGNAL(directoryChanged(const QString &)), this,
+                       SLOT(onFileSystemChanged(const QString &)));
+  
+  // when the scene switched, update the path of the scene location node
+  TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene();
+  //ret = ret && connect(sceneHandle, SIGNAL(sceneSwitched()), this,
+  //                     SLOT(onSceneSwitched()));
+  ret = ret && connect(sceneHandle, SIGNAL(nameSceneChanged()), this,
+                       SLOT(onSceneSwitched()));
+
+  //onSceneSwitched();
+
+  // store the first item("Root") in the history
+  m_indexHistoryList.append(m_folderTreeView->currentIndex());
+  m_currentPosition = 0;
+
+  refreshHistoryButtons();
+
+  assert(ret);
+}
+
+//-----------------------------------------------------------------------------
+
+SceneBrowser::~SceneBrowser() {}
+
+//-----------------------------------------------------------------------------
+/*! when the m_folderName is edited, move the current folder accordingly
+ */
+void SceneBrowser::onFolderEdited() {
+  TFilePath inputPath(m_folderName->text().toStdWString());
+  QModelIndex index = DvDirModel::instance()->getIndexByPath(inputPath);
+
+  // If there is no node matched
+  if (!index.isValid()) {
+    QMessageBox::warning(this, tr("Open folder failed"),
+                         tr("The input folder path was invalid."));
+    return;
+  }
+  m_folderTreeView->collapseAll();
+
+  m_folderTreeView->setCurrentIndex(index);
+
+  // expand the folder tree
+  QModelIndex tmpIndex = index;
+  while (tmpIndex.isValid()) {
+    m_folderTreeView->expand(tmpIndex);
+    tmpIndex = tmpIndex.parent();
+  }
+
+  m_folderTreeView->scrollTo(index);
+  m_folderTreeView->update();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::storeFolderHistory() {
+  QModelIndex currentModelIndex = m_folderTreeView->currentIndex();
+
+  if (!currentModelIndex.isValid()) return;
+
+  if (m_indexHistoryList[m_currentPosition] == currentModelIndex) return;
+
+  // If there is no next history item, then create it
+  if (m_currentPosition == m_indexHistoryList.size() - 1) {
+    m_indexHistoryList << currentModelIndex;
+    m_currentPosition++;
+  }
+  // If the next hitory item is the same as the current one, just move to it
+  else if (m_indexHistoryList[m_currentPosition + 1] == currentModelIndex) {
+    m_currentPosition++;
+  }
+  // If the next history item is different from the current one, then replace
+  // with the new one
+  else {
+    int size = m_indexHistoryList.size();
+    // remove the old history items
+    for (int i = m_currentPosition + 1; i < size; i++)
+      m_indexHistoryList.removeLast();
+    m_indexHistoryList << currentModelIndex;
+    m_currentPosition++;
+  }
+  refreshHistoryButtons();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::refreshHistoryButtons() {
+  emit historyChanged((m_currentPosition != 0),
+                      (m_currentPosition != m_indexHistoryList.size() - 1));
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onBackButtonPushed() {
+  if (m_currentPosition == 0) return;
+  m_currentPosition--;
+  QModelIndex currentIndex = m_indexHistoryList[m_currentPosition];
+  m_folderTreeView->setCurrentIndex(currentIndex);
+  m_folderTreeView->collapseAll();
+  while (currentIndex.isValid()) {
+    currentIndex = currentIndex.parent();
+    m_folderTreeView->expand(currentIndex);
+  }
+  m_folderTreeView->update();
+
+  refreshHistoryButtons();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onFwdButtonPushed() {
+  if (m_currentPosition >= m_indexHistoryList.size() - 1) return;
+  m_currentPosition++;
+  QModelIndex currentIndex = m_indexHistoryList[m_currentPosition];
+  m_folderTreeView->setCurrentIndex(currentIndex);
+  m_folderTreeView->collapseAll();
+  while (currentIndex.isValid()) {
+    currentIndex = currentIndex.parent();
+    m_folderTreeView->expand(currentIndex);
+  }
+  m_folderTreeView->update();
+
+  refreshHistoryButtons();
+}
+
+//-----------------------------------------------------------------------------
+/*! clear the history when the tree date is replaced
+ */
+void SceneBrowser::clearHistory() {
+  int size = m_indexHistoryList.size();
+  // leave the last item
+  for (int i = 1; i < size; i++) m_indexHistoryList.removeLast();
+  m_currentPosition = 0;
+  refreshHistoryButtons();
+}
+
+//-----------------------------------------------------------------------------
+/*! update the current folder when changes detected from QFileSystemWatcher
+ */
+void SceneBrowser::onFileSystemChanged(const QString &folderPath) {
+  if (folderPath != m_folder.getQString()) return;
+  // changes may create/delete of folder, so update the DvDirModel
+  QModelIndex parentFolderIndex = m_folderTreeView->currentIndex();
+  DvDirModel::instance()->refresh(parentFolderIndex);
+
+  refreshCurrentFolderItems();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::sortByDataModel(DataType dataType, bool isDiscendent) {
+  struct locals {
+    static inline bool itemLess(int aIdx, int bIdx, SceneBrowser &fb,
+                                DataType dataType) {
+      return (fb.compareData(dataType, aIdx, bIdx) > 0);
+    }
+
+    static inline bool indexLess(int aIdx, int bIdx,
+                                 const std::vector<int> &vec) {
+      return (vec[aIdx] < vec[bIdx]);
+    }
+
+    static inline int complement(int val, int max) {
+      return (assert(0 <= val && val <= max), max - val);
+    }
+  };  // locals
+
+  if (dataType != getCurrentOrderType()) {
+    // Build the permutation table
+    std::vector<int> new2OldIdx(
+        boost::make_counting_iterator(0),
+        boost::make_counting_iterator(int(m_items.size())));
+
+    std::stable_sort(
+        new2OldIdx.begin(), new2OldIdx.end(),
+        boost::bind(locals::itemLess, _1, _2, boost::ref(*this), dataType));
+
+    // Use the renumbering table to permutate elements
+    std::vector<Item>(
+        boost::make_permutation_iterator(m_items.begin(), new2OldIdx.begin()),
+        boost::make_permutation_iterator(m_items.begin(), new2OldIdx.end()))
+        .swap(m_items);
+
+    // Use the permutation table to update current file selection, if any
+    FileSelection *fs =
+        static_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+
+    if (!fs->isEmpty()) {
+      std::vector<int> old2NewIdx(
+          boost::make_counting_iterator(0),
+          boost::make_counting_iterator(int(m_items.size())));
+
+      std::sort(old2NewIdx.begin(), old2NewIdx.end(),
+                boost::bind(locals::indexLess, _1, _2, boost::ref(new2OldIdx)));
+
+      std::vector<int> newSelectedIndices;
+      tcg::substitute(
+          newSelectedIndices,
+          tcg::permuted_range(old2NewIdx, fs->getSelectedIndices() |
+                                              ba::filtered(boost::bind(
+                                                  std::less<int>(), _1,
+                                                  int(old2NewIdx.size())))));
+
+      fs->select(!newSelectedIndices.empty() ? &newSelectedIndices.front() : 0,
+                 int(newSelectedIndices.size()));
+    }
+
+    setIsDiscendentOrder(true);
+    setOrderType(dataType);
+  }
+
+  // Reverse lists if necessary
+  if (isDiscendentOrder() != isDiscendent) {
+    std::reverse(m_items.begin(), m_items.end());
+
+    // Reverse file selection, if any
+    FileSelection *fs =
+        dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+
+    if (!fs->isEmpty()) {
+      int iCount = int(m_items.size()), lastIdx = iCount - 1;
+
+      std::vector<int> newSelectedIndices;
+      tcg::substitute(
+          newSelectedIndices,
+          fs->getSelectedIndices() |
+              ba::filtered(boost::bind(std::less<int>(), _1, iCount)) |
+              ba::transformed(boost::bind(locals::complement, _1, lastIdx)));
+
+      fs->select(!newSelectedIndices.empty() ? &newSelectedIndices.front() : 0,
+                 int(newSelectedIndices.size()));
+    }
+
+    setIsDiscendentOrder(isDiscendent);
+  }
+
+  m_itemViewer->getPanel()->update();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::setFilterTypes(const QStringList &types) { m_filter = types; }
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::addFilterType(const QString &type) {
+  if (!m_filter.contains(type)) m_filter.push_back(type);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::removeFilterType(const QString &type) {
+  m_filter.removeAll(type);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::refreshCurrentFolderItems() {
+  m_items.clear();
+
+  // put the parent directory item
+  //TFilePath parentFp = m_folder.getParentDir();
+  //if (parentFp != TFilePath("") && parentFp != m_folder)
+  //  m_items.push_back(Item(parentFp, true, false));
+
+  // register the file items
+  if (m_folder != TFilePath()) {
+    TFilePathSet files;
+    TFilePathSet all_files;  // for updating m_multiFileItemMap
+
+    TFileStatus fpStatus(m_folder);
+    // if the item is link, then set the link target of it
+    if (fpStatus.isLink()) {
+      QFileInfo info(toQString(m_folder));
+      setFolder(TFilePath(info.symLinkTarget().toStdWString()));
+      return;
+    }
+    if (fpStatus.doesExist() && fpStatus.isDirectory() &&
+        fpStatus.isReadable()) {
+      try {
+        TSystem::readDirectory(files, all_files, m_folder);
+      } catch (...) {
+      }
+    }
+    TFilePathSet::iterator it;
+    for (it = files.begin(); it != files.end(); ++it) {
+      // skip the plt file (Palette file for TOONZ 4.6 and earlier)
+      if (it->getType() == "plt") continue;
+
+      // filter the file
+      else if (m_filter.isEmpty()) {
+        if (it->getType() != "tnz" && it->getType() != "scr" &&
+            it->getType() != "tnzbat" && it->getType() != "mpath" &&
+            it->getType() != "curve" && it->getType() != "tpl" &&
+            TFileType::getInfo(*it) == TFileType::UNKNOW_FILE)
+          continue;
+      } else if (m_filter.contains(QString::fromStdString(it->getType())))
+        continue;
+      // store the filtered file paths
+      m_items.push_back(Item(*it));
+    }
+
+    // update the m_multiFileItemMap
+    m_multiFileItemMap.clear();
+
+    for (it = all_files.begin(); it != all_files.end(); it++) {
+      TFrameId tFrameId;
+      tFrameId = it->getFrame();
+      TFilePath levelName(it->getLevelName());
+
+      if (levelName.isLevelName()) {
+        Item &levelItem = m_multiFileItemMap[levelName];
+
+        // TODO:
+        // とりあえず残すが、FileInfoの取得に時間がかかるようならオプション化も検討
+        // 2015/12/28 shun_iwasawa
+        QFileInfo fileInfo(QString::fromStdWString(it->getWideString()));
+        // Update level infos
+        if (levelItem.m_creationDate.isNull() ||
+            (fileInfo.created() < levelItem.m_creationDate))
+          levelItem.m_creationDate = fileInfo.created();
+        if (levelItem.m_modifiedDate.isNull() ||
+            (fileInfo.lastModified() > levelItem.m_modifiedDate))
+          levelItem.m_modifiedDate = fileInfo.lastModified();
+        levelItem.m_fileSize += fileInfo.size();
+
+        // store frameId
+        levelItem.m_frameIds.push_back(tFrameId);
+
+        levelItem.m_frameCount++;
+      }
+    }
+  }
+
+  // Set Missing Version Control Items
+  int missingItemCount          = 0;
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (node) {
+    QList<TFilePath> list = node->getMissingFiles();
+    missingItemCount      = list.size();
+    for (int i = 0; i < missingItemCount; i++)
+      m_items.push_back(Item(list.at(i)));
+  }
+
+  // Refresh Data (fill Item field)
+  refreshData();
+
+  // If I added some missing items I need to sort items.
+  if (missingItemCount > 0) {
+    DataType currentDataType = getCurrentOrderType();
+    int i;
+    for (i = 1; i < m_items.size(); i++) {
+      int index = i;
+      while (index > 0 && compareData(currentDataType, index - 1, index) > 0) {
+        std::swap(m_items[index - 1], m_items[index]);
+        index = index - 1;
+      }
+    }
+  }
+  // update the ordering rules
+  bool discendentOrder     = isDiscendentOrder();
+  DataType currentDataType = getCurrentOrderType();
+  setOrderType(Name);
+  setIsDiscendentOrder(true);
+  sortByDataModel(currentDataType, discendentOrder);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::setFolder(const TFilePath &fp, bool expandNode,
+                            bool forceUpdate) {
+  if (fp == m_folder && !forceUpdate) return;
+
+  // set the current folder path
+  m_folder        = fp;
+  m_dayDateString = "";
+  // set the folder name
+  if (fp == TFilePath())
+    m_folderName->setText("");
+  else
+    m_folderName->setText(toQString(fp));
+
+  refreshCurrentFolderItems();
+
+  if (!TFileStatus(fp).isLink())
+    m_folderTreeView->setCurrentNode(fp, expandNode);
+}
+
+//-----------------------------------------------------------------------------
+/*! process when inputting the folder which is not regitered in the folder tree
+   (e.g. UNC path in Windows)
+ */
+void SceneBrowser::setUnregisteredFolder(const TFilePath &fp) {
+  if (fp != TFilePath()) {
+    TFileStatus fpStatus(fp);
+    // if the item is link, then set the link target of it
+    if (fpStatus.isLink()) {
+      QFileInfo info(toQString(fp));
+      setFolder(TFilePath(info.symLinkTarget().toStdWString()));
+      return;
+    }
+
+    // get both the folder & file list by readDirectory and
+    // readDirectory_Dir_ReadExe
+    TFilePathSet folders;
+    TFilePathSet files;
+    // for updating m_multiFileItemMap
+    TFilePathSet all_files;
+
+    if (fpStatus.doesExist() && fpStatus.isDirectory() &&
+        fpStatus.isReadable()) {
+      try {
+        TSystem::readDirectory(files, all_files, fp);
+        TSystem::readDirectory_Dir_ReadExe(folders, fp);
+      } catch (...) {
+      }
+    }
+
+    TFilePathSet::iterator it;
+
+    // register all folder items
+    for (it = folders.begin(); it != folders.end(); ++it) {
+      if (TFileStatus(*it).isLink())
+        m_items.push_back(Item(*it, true, true));
+      else
+        m_items.push_back(Item(*it, true, false));
+    }
+
+    for (it = files.begin(); it != files.end(); ++it) {
+      // skip the plt file (Palette file for TOONZ 4.6 and earlier)
+      if (it->getType() == "plt") continue;
+
+      // filtering
+      else if (m_filter.isEmpty()) {
+        if (it->getType() != "tnz" && it->getType() != "scr" &&
+            it->getType() != "tnzbat" && it->getType() != "mpath" &&
+            it->getType() != "curve" && it->getType() != "tpl" &&
+            TFileType::getInfo(*it) == TFileType::UNKNOW_FILE)
+          continue;
+      } else if (m_filter.contains(QString::fromStdString(it->getType())))
+        continue;
+
+      m_items.push_back(Item(*it));
+    }
+
+    // update the m_multiFileItemMap
+    m_multiFileItemMap.clear();
+    for (it = all_files.begin(); it != all_files.end(); it++) {
+      TFilePath levelName(it->getLevelName());
+      if (levelName.isLevelName()) {
+        Item &levelItem = m_multiFileItemMap[levelName];
+        levelItem.m_frameIds.push_back(it->getFrame());
+        levelItem.m_frameCount++;
+      }
+    }
+  }
+  // for all items in the folder, retrieve the file names(m_name) from the
+  // paths(m_path)
+  refreshData();
+
+  // update the ordering rules
+  bool discendentOrder     = isDiscendentOrder();
+  DataType currentDataType = getCurrentOrderType();
+  setOrderType(Name);
+  setIsDiscendentOrder(true);
+  sortByDataModel(currentDataType, discendentOrder);
+
+  m_itemViewer->repaint();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::setHistoryDay(std::string dayDateString) {
+  m_folder                = TFilePath();
+  m_dayDateString         = dayDateString;
+  const History::Day *day = History::instance()->getDay(dayDateString);
+  m_items.clear();
+  if (day == 0) {
+    m_folderName->setText("");
+  } else {
+    m_folderName->setText(QString::fromStdString(dayDateString));
+    std::vector<TFilePath> files;
+    day->getFiles(files);
+    std::vector<TFilePath>::iterator it;
+    for (it = files.begin(); it != files.end(); ++it)
+      m_items.push_back(Item(*it));
+  }
+  refreshData();
+}
+
+//-----------------------------------------------------------------------------
+/*! for all items in the folder, retrieve the file names(m_name) from the
+ * paths(m_path)
+ */
+void SceneBrowser::refreshData() {
+  std::vector<Item>::iterator it;
+  for (it = m_items.begin(); it != m_items.end(); ++it) {
+    if (it->m_name == QString(""))
+      it->m_name = toQString(it->m_path.withoutParentDir());
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+int SceneBrowser::getItemCount() const { return m_items.size(); }
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::readInfo(Item &item) {
+  TFilePath fp = item.m_path;
+  QFileInfo info(toQString(fp));
+  if (info.exists()) {
+    item.m_creationDate = info.created();
+    item.m_modifiedDate = info.lastModified();
+    item.m_fileType     = info.suffix();
+    item.m_fileSize     = info.size();
+    if (fp.getType() == "tnz") {
+      ToonzScene scene;
+      try {
+        item.m_frameCount = scene.loadFrameCount(fp);
+      } catch (...) {
+      }
+    } else
+      readFrameCount(item);
+
+    item.m_validInfo = true;
+  } else if (fp.isLevelName())  // for levels johndoe..tif etc.
+  {
+    try {
+      // Find this level's item
+      std::map<TFilePath, Item>::iterator it =
+          m_multiFileItemMap.find(TFilePath(item.m_path.getLevelName()));
+      if (it == m_multiFileItemMap.end()) throw "";
+
+      item.m_creationDate = it->second.m_creationDate;
+      item.m_modifiedDate = it->second.m_modifiedDate;
+      item.m_fileType     = it->second.m_fileType;
+      item.m_fileSize     = it->second.m_fileSize;
+      item.m_frameCount   = it->second.m_frameCount;
+      item.m_validInfo    = true;
+
+      // keep the list of frameIds at the first time and try to reuse it.
+      item.m_frameIds = it->second.m_frameIds;
+
+      // The old way
+      /*TLevelReaderP lr(fp);
+item.m_frameCount = lr->loadInfo()->getFrameCount();
+item.m_creationDate = QDateTime();
+item.m_modifiedDate = QDateTime();
+item.m_fileSize = -1;
+item.m_validInfo = true;*/
+    } catch (...) {
+      item.m_frameCount = 0;
+    }
+  }
+
+  item.m_validInfo = true;
+}
+
+//-----------------------------------------------------------------------------
+
+//! Frame count needs a special access function for viewable types - for they
+//! are
+//! calculated by using a dedicated thread and therefore cannot be simply
+//! classified as *valid* or *invalid* infos...
+void SceneBrowser::readFrameCount(Item &item) {
+  if (TFileType::isViewable(TFileType::getInfo(item.m_path))) {
+    if (isMultipleFrameType(item.m_path.getType()))
+      item.m_frameCount = m_frameCountReader.getFrameCount(item.m_path);
+    else
+      item.m_frameCount = 1;
+  } else
+    item.m_frameCount = 0;
+}
+
+//-----------------------------------------------------------------------------
+
+QVariant SceneBrowser::getItemData(int index, DataType dataType,
+                                  bool isSelected) {
+  if (index < 0 || index >= (int)m_items.size()) return QVariant();
+  Item &item = m_items[index];
+  if (dataType == Name) {
+    // show two dots( ".." ) for the paret directory item
+    if (item.m_path == m_folder.getParentDir())
+      return QString("..");
+    else
+      return item.m_name;
+  } else if (dataType == Thumbnail) {
+    QSize iconSize = m_itemViewer->getPanel()->getIconSize();
+    // parent folder icons
+    if (item.m_path == m_folder.getParentDir()) {
+      static QPixmap folderUpPixmap(svgToPixmap(":Resources/folderup_icon.svg",
+                                                iconSize, Qt::KeepAspectRatio));
+      return folderUpPixmap;
+    }
+    // folder icons
+    else if (item.m_isFolder) {
+      if (item.m_isLink) {
+        static QPixmap linkIcon(svgToPixmap(":Resources/link_icon.svg",
+                                            iconSize, Qt::KeepAspectRatio));
+        return linkIcon;
+      } else {
+        static QPixmap folderIcon(svgToPixmap(":Resources/folder_icon.svg",
+                                              iconSize, Qt::KeepAspectRatio));
+        return folderIcon;
+      }
+    }
+
+    QPixmap pixmap = IconGenerator::instance()->getIcon(item.m_path);
+    if (pixmap.isNull()) {
+      pixmap = QPixmap(iconSize);
+      pixmap.fill(Qt::white);
+    }
+    return scalePixmapKeepingAspectRatio(pixmap, iconSize, Qt::transparent);
+  } else if (dataType == Icon)
+    return QVariant();
+  else if (dataType == ToolTip || dataType == FullPath)
+    return QString::fromStdWString(item.m_path.getWideString());
+
+  else if (dataType == IsFolder) {
+    return item.m_isFolder;
+  }
+
+  if (!item.m_validInfo) {
+    readInfo(item);
+    if (!item.m_validInfo) return QVariant();
+  }
+
+  if (dataType == CreationDate) return item.m_creationDate;
+  if (dataType == ModifiedDate) return item.m_modifiedDate;
+  if (dataType == FileType) {
+    if (item.m_isLink)
+      return QString("<LINK>");
+    else if (item.m_isFolder)
+      return QString("<DIR>");
+    else
+      return QString::fromStdString(item.m_path.getType()).toUpper();
+  } else if (dataType == FileSize)
+    return (item.m_fileSize == -1) ? QVariant() : item.m_fileSize;
+  else if (dataType == FrameCount) {
+    if (item.m_frameCount == -1) readFrameCount(item);
+    return item.m_frameCount;
+  } else if (dataType == PlayAvailable) {
+    std::string type = item.m_path.getType();
+    if (item.m_frameCount > 1 && type != "tzp" && type != "tzu") return true;
+    return false;
+  } else if (dataType == VersionControlStatus) {
+    return getItemVersionControlStatus(item);
+  } else
+    return QVariant();
+}
+
+//-----------------------------------------------------------------------------
+
+bool SceneBrowser::isSceneItem(int index) const {
+  return 0 <= index && index < (int)m_items.size() &&
+         m_items[index].m_path.getType() == "tnz";
+}
+
+//-----------------------------------------------------------------------------
+
+bool SceneBrowser::canRenameItem(int index) const {
+  // se sto guardando la history non posso rinominare nulla
+  if (getFolder() == TFilePath()) return false;
+  if (index < 0 || index >= (int)m_items.size()) return false;
+  // for now, disable rename for folders
+  if (m_items[index].m_isFolder) return false;
+  TFilePath fp = m_items[index].m_path;
+  return TFileStatus(fp).doesExist();
+}
+
+//-----------------------------------------------------------------------------
+
+int SceneBrowser::findIndexWithPath(TFilePath path) {
+  int i;
+  for (i = 0; i < m_items.size(); i++)
+    if (m_items[i].m_path == path) return i;
+  return -1;
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::renameItem(int index, const QString &newName) {
+  if (getFolder() == TFilePath()) return;
+  if (index < 0 || index >= (int)m_items.size()) return;
+
+  TFilePath fp    = m_items[index].m_path;
+  TFilePath newFp = fp;
+  if (renameFile(newFp, newName)) {
+    m_items[index].m_name = QString::fromStdWString(newFp.getLevelNameW());
+    m_items[index].m_path = newFp;
+
+    // ho rinominato anche la palette devo aggiornarla.
+    if (newFp.getType() == "tlv" || newFp.getType() == "tzp" ||
+        newFp.getType() == "tzu") {
+      const char *type = (newFp.getType() == "tlv") ? "tpl" : "plt";
+      int paletteIndex = findIndexWithPath(fp.withNoFrame().withType(type));
+      if (paletteIndex >= 0) {
+        TFilePath palettePath = newFp.withNoFrame().withType(type);
+        m_items[paletteIndex].m_name =
+            QString::fromStdWString(palettePath.getLevelNameW());
+        m_items[paletteIndex].m_path = palettePath;
+      }
+    }
+    m_itemViewer->update();
+
+    if (fp.getType() == "tnz") {
+      // ho cambiato il folder _files. Devo aggiornare il folder che lo contiene
+      // nel tree view
+      QModelIndex index = m_folderTreeView->currentIndex();
+      if (index.isValid()) {
+        DvDirModel::instance()->refresh(index);
+        // m_folderTreeView->getDvDirModel()->refresh(index);
+        m_folderTreeView->update();
+      }
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+bool SceneBrowser::renameFile(TFilePath &fp, QString newName) {
+  if (isSpaceString(newName)) return true;
+
+  TFilePath newFp(newName.toStdWString());
+  if (newFp.getType() != "" && newFp.getType() != fp.getType()) {
+    DVGui::error(tr("Can't change file extension"));
+    return false;
+  }
+  if (newFp.getType() == "") newFp = newFp.withType(fp.getType());
+  if (newFp.getFrame() != TFrameId::EMPTY_FRAME &&
+      newFp.getFrame() != TFrameId::NO_FRAME) {
+    DVGui::error(tr("Can't set a drawing number"));
+    return false;
+  }
+  if (newFp.getDots() != fp.getDots()) {
+    if (fp.getDots() == ".")
+      newFp = newFp.withNoFrame();
+    else if (fp.getDots() == "..")
+      newFp = newFp.withFrame(TFrameId::EMPTY_FRAME);
+  }
+  newFp = newFp.withParentDir(fp.getParentDir());
+
+  // se sono uguali non devo rinominare nulla
+  if (newFp == fp) return false;
+
+  if (TSystem::doesExistFileOrLevel(newFp)) {
+    DVGui::error(tr("Can't rename. File already exists: ") + toQString(newFp));
+    return false;
+  }
+
+  try {
+    TSystem::renameFileOrLevel_throw(newFp, fp, true);
+    IconGenerator::instance()->remove(fp);
+    if (fp.getType() == "tnz") {
+      /* TFilePath folder = fp.getParentDir() + (fp.getName() + "_files");
+TFilePath newFolder = newFp.getParentDir() + (newFp.getName() + "_files");
+TSystem::renameFile(newFolder, folder);
+*/
+      TFilePath sceneIconFp    = ToonzScene::getIconPath(fp);
+      TFilePath sceneIconNewFp = ToonzScene::getIconPath(newFp);
+      if (TFileStatus(sceneIconFp).doesExist()) {
+        if (TFileStatus(sceneIconNewFp).doesExist())
+          TSystem::deleteFile(sceneIconNewFp);
+        TSystem::renameFile(sceneIconNewFp, sceneIconFp);
+      }
+    }
+
+  } catch (...) {
+    DVGui::error(tr("Couldn't rename ") + toQString(fp) + " to " +
+                 toQString(newFp));
+    return false;
+  }
+
+  fp = newFp;
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+
+QMenu *SceneBrowser::getContextMenu(QWidget *parent, int index) {
+  auto isOldLevelType = [](TFilePath &path) -> bool {
+    return path.getType() == "tzp" || path.getType() == "tzu";
+  };
+
+  bool ret = true;
+
+  // TODO: spostare in questa classe anche la definizione delle azioni?
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return 0;
+  std::vector<TFilePath> files;
+  fs->getSelectedFiles(files);
+
+  QMenu *menu        = new QMenu(parent);
+  CommandManager *cm = CommandManager::instance();
+
+  if (files.empty()) {
+    menu->addAction(cm->getAction(MI_ShowFolderContents));
+    menu->addAction(cm->getAction(MI_SelectAll));
+    if (!Preferences::instance()->isWatchFileSystemEnabled()) {
+      menu->addAction(cm->getAction(MI_RefreshTree));
+    }
+    return menu;
+  }
+
+  if (files.size() == 1 && files[0].getType() == "tnz") {
+    menu->addAction(cm->getAction(MI_LoadScene));
+  }
+
+  bool areResources = true;
+  bool areScenes    = false;
+  int i, j;
+  for (i = 0; i < (int)files.size(); i++) {
+    TFileType::Type type = TFileType::getInfo(files[i]);
+    if (areResources && !TFileType::isResource(type)) areResources = false;
+    if (!areScenes && TFileType::isScene(type)) areScenes = true;
+  }
+
+  bool areFullcolor = true;
+  for (i = 0; i < (int)files.size(); i++) {
+    TFileType::Type type = TFileType::getInfo(files[i]);
+    if (!TFileType::isFullColor(type)) {
+      areFullcolor = false;
+      break;
+    }
+  }
+
+  TFilePath clickedFile;
+  if (0 <= index && index < (int)m_items.size())
+    clickedFile = m_items[index].m_path;
+
+  if (areResources) {
+    QString title;
+    if (clickedFile != TFilePath() && clickedFile.getType() == "tnz")
+      title = tr("Load As Sub-xsheet");
+    else
+      title = tr("Load");
+    QAction *action = new QAction(title, menu);
+    ret             = ret &&
+          connect(action, SIGNAL(triggered()), this, SLOT(loadResources()));
+    menu->addAction(action);
+    menu->addSeparator();
+  }
+
+  menu->addAction(cm->getAction(MI_DuplicateFile));
+  if (!areScenes) {
+    menu->addAction(cm->getAction(MI_Copy));
+    menu->addAction(cm->getAction(MI_Paste));
+  }
+  menu->addAction(cm->getAction(MI_Clear));
+  menu->addAction(cm->getAction(MI_ShowFolderContents));
+  menu->addAction(cm->getAction(MI_SelectAll));
+  menu->addAction(cm->getAction(MI_FileInfo));
+  if (!clickedFile.isEmpty() &&
+      (clickedFile.getType() == "tnz" || clickedFile.getType() == "tab")) {
+    menu->addSeparator();
+    menu->addAction(cm->getAction(MI_AddToBatchRenderList));
+    menu->addAction(cm->getAction(MI_AddToBatchCleanupList));
+  }
+
+  for (i = 0; i < files.size(); i++)
+    if (!TFileType::isViewable(TFileType::getInfo(files[i]))) break;
+  if (i == files.size()) {
+    std::string type = files[0].getType();
+    for (j = 0; j < files.size(); j++)
+      if (isOldLevelType(files[j])) break;
+    if (j == files.size()) menu->addAction(cm->getAction(MI_ViewFile));
+
+    for (j = 0; j < files.size(); j++) {
+      if ((files[0].getType() == "pli" && files[j].getType() != "pli") ||
+          (files[0].getType() != "pli" && files[j].getType() == "pli"))
+        break;
+      else if ((isOldLevelType(files[0]) && !isOldLevelType(files[j])) ||
+               (!isOldLevelType(files[0]) && isOldLevelType(files[j])))
+        break;
+    }
+    if (j == files.size()) {
+      menu->addAction(cm->getAction(MI_ConvertFiles));
+      // iwsw commented out temporarily
+      // menu->addAction(cm->getAction(MI_ToonShadedImageToTLV));
+    }
+    if (areFullcolor) menu->addAction(cm->getAction(MI_SeparateColors));
+
+    if (!areFullcolor) menu->addSeparator();
+  }
+  if (files.size() == 1 && files[0].getType() != "tnz") {
+    QAction *action = new QAction(tr("Rename"), menu);
+    ret             = ret && connect(action, SIGNAL(triggered()), this,
+                         SLOT(renameAsToonzLevel()));
+    menu->addAction(action);
+  }
+#ifdef LEVO
+
+  if (files.size() == 2 &&
+      (files[0].getType() == "tif" || files[0].getType() == "tiff" ||
+       files[0].getType() == "png" || files[0].getType() == "TIF" ||
+       files[0].getType() == "TIFF" || files[0].getType() == "PNG") &&
+      (files[1].getType() == "tif" || files[1].getType() == "tiff" ||
+       files[1].getType() == "png" || files[1].getType() == "TIF" ||
+       files[1].getType() == "TIFF" || files[1].getType() == "PNG")) {
+    QAction *action = new QAction(tr("Convert to Painted TLV"), menu);
+    ret             = ret && connect(action, SIGNAL(triggered()), this,
+                         SLOT(convertToPaintedTlv()));
+    menu->addAction(action);
+  }
+  if (areFullcolor) {
+    QAction *action = new QAction(tr("Convert to Unpainted TLV"), menu);
+    ret             = ret && connect(action, SIGNAL(triggered()), this,
+                         SLOT(convertToUnpaintedTlv()));
+    menu->addAction(action);
+    menu->addSeparator();
+  }
+#endif
+
+  if (!clickedFile.isEmpty() && (clickedFile.getType() == "tnz")) {
+    menu->addSeparator();
+    menu->addAction(cm->getAction(MI_CollectAssets));
+    menu->addAction(cm->getAction(MI_ImportScenes));
+    menu->addAction(cm->getAction(MI_ExportScenes));
+  }
+
+  DvDirVersionControlNode *node = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (node) {
+    // Check Version Control Status
+    DvItemListModel::Status status =
+        (DvItemListModel::Status)m_itemViewer->getModel()
+            ->getItemData(index, DvItemListModel::VersionControlStatus)
+            .toInt();
+
+    // Remove the added actions
+    if (status == DvItemListModel::VC_Missing) menu->clear();
+
+    QMenu *vcMenu = new QMenu(tr("Version Control"), parent);
+    QAction *action;
+
+    if (status == DvItemListModel::VC_ReadOnly ||
+        (status == DvItemListModel::VC_ToUpdate && files.size() == 1)) {
+      if (status == DvItemListModel::VC_ReadOnly) {
+        action = vcMenu->addAction(tr("Edit"));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(editVersionControl()));
+
+        TFilePath path       = files.at(0);
+        std::string fileType = path.getType();
+        if (fileType == "tlv" || fileType == "pli" || path.getDots() == "..") {
+          action = vcMenu->addAction(tr("Edit Frame Range..."));
+          ret    = ret && connect(action, SIGNAL(triggered()), this,
+                               SLOT(editFrameRangeVersionControl()));
+        }
+      } else {
+        action = vcMenu->addAction(tr("Edit"));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(updateAndEditVersionControl()));
+      }
+    }
+
+    if (status == DvItemListModel::VC_Modified) {
+      action = vcMenu->addAction(tr("Put..."));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(putVersionControl()));
+
+      action = vcMenu->addAction(tr("Revert"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(revertVersionControl()));
+    }
+
+    if (status == DvItemListModel::VC_ReadOnly ||
+        status == DvItemListModel::VC_ToUpdate) {
+      action = vcMenu->addAction(tr("Get"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(getVersionControl()));
+
+      if (status == DvItemListModel::VC_ReadOnly) {
+        action = vcMenu->addAction(tr("Delete"));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(deleteVersionControl()));
+      }
+
+      vcMenu->addSeparator();
+
+      if (files.size() == 1) {
+        action         = vcMenu->addAction(tr("Get Revision..."));
+        TFilePath path = files.at(0);
+        if (path.getDots() == "..")
+          ret = ret && connect(action, SIGNAL(triggered()), this,
+                               SLOT(getRevisionVersionControl()));
+        else
+          ret = ret && connect(action, SIGNAL(triggered()), this,
+                               SLOT(getRevisionHistory()));
+      } else if (files.size() > 1) {
+        action = vcMenu->addAction("Get Revision...");
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(getRevisionVersionControl()));
+      }
+    }
+
+    if (status == DvItemListModel::VC_Edited) {
+      action = vcMenu->addAction(tr("Unlock"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(unlockVersionControl()));
+    }
+
+    if (status == DvItemListModel::VC_Unversioned) {
+      action = vcMenu->addAction(tr("Put..."));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(putVersionControl()));
+    }
+
+    if (status == DvItemListModel::VC_Locked && files.size() == 1) {
+      action = vcMenu->addAction(tr("Unlock"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(unlockVersionControl()));
+
+      action = vcMenu->addAction(tr("Edit Info"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(showLockInformation()));
+    }
+
+    if (status == DvItemListModel::VC_Missing) {
+      action = vcMenu->addAction(tr("Get"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(getVersionControl()));
+
+      if (files.size() == 1) {
+        vcMenu->addSeparator();
+        action         = vcMenu->addAction(tr("Revision History..."));
+        TFilePath path = files.at(0);
+        if (path.getDots() == "..")
+          ret = ret && connect(action, SIGNAL(triggered()), this,
+                               SLOT(getRevisionVersionControl()));
+        else
+          ret = ret && connect(action, SIGNAL(triggered()), this,
+                               SLOT(getRevisionHistory()));
+      }
+    }
+
+    if (status == DvItemListModel::VC_PartialLocked) {
+      action = vcMenu->addAction(tr("Get"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(getVersionControl()));
+      if (files.size() == 1) {
+        action = vcMenu->addAction(tr("Edit Frame Range..."));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(editFrameRangeVersionControl()));
+
+        action = vcMenu->addAction(tr("Edit Info"));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(showFrameRangeLockInfo()));
+      }
+
+    } else if (status == DvItemListModel::VC_PartialEdited) {
+      action = vcMenu->addAction(tr("Get"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(getVersionControl()));
+
+      if (files.size() == 1) {
+        action = vcMenu->addAction(tr("Unlock Frame Range"));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(unlockFrameRangeVersionControl()));
+
+        action = vcMenu->addAction(tr("Edit Info"));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(showFrameRangeLockInfo()));
+      }
+    } else if (status == DvItemListModel::VC_PartialModified) {
+      action = vcMenu->addAction(tr("Get"));
+      ret    = ret && connect(action, SIGNAL(triggered()), this,
+                           SLOT(getVersionControl()));
+
+      if (files.size() == 1) {
+        action = vcMenu->addAction(tr("Put..."));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(putFrameRangeVersionControl()));
+
+        action = vcMenu->addAction(tr("Revert"));
+        ret    = ret && connect(action, SIGNAL(triggered()), this,
+                             SLOT(revertFrameRangeVersionControl()));
+      }
+    }
+
+    if (!vcMenu->isEmpty()) {
+      menu->addSeparator();
+      menu->addMenu(vcMenu);
+    }
+  }
+
+  if (!Preferences::instance()->isWatchFileSystemEnabled()) {
+    menu->addSeparator();
+    menu->addAction(cm->getAction(MI_RefreshTree));
+  }
+
+  assert(ret);
+
+  return menu;
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::startDragDrop() {
+  TRepetitionGuard guard;
+  if (!guard.hasLock()) return;
+
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  std::vector<TFilePath> files;
+  fs->getSelectedFiles(files);
+  if (files.empty()) return;
+
+  QList<QUrl> urls;
+  for (int i = 0; i < (int)files.size(); i++) {
+    if (TSystem::doesExistFileOrLevel(files[i]))
+      urls.append(QUrl::fromLocalFile(
+          QString::fromStdWString(files[i].getWideString())));
+  }
+  if (urls.isEmpty()) return;
+
+  QMimeData *mimeData = new QMimeData;
+  mimeData->setUrls(urls);
+  QDrag *drag    = new QDrag(this);
+  QSize iconSize = m_itemViewer->getPanel()->getIconSize();
+  QPixmap icon   = IconGenerator::instance()->getIcon(files[0]);
+  QPixmap dropThumbnail =
+      scalePixmapKeepingAspectRatio(icon, iconSize, Qt::transparent);
+  if (!dropThumbnail.isNull()) drag->setPixmap(dropThumbnail);
+  drag->setMimeData(mimeData);
+  Qt::DropAction dropAction = drag->exec(Qt::CopyAction);
+}
+
+//-----------------------------------------------------------------------------
+
+bool SceneBrowser::dropMimeData(QTreeWidgetItem *parent, int index,
+                               const QMimeData *data, Qt::DropAction action) {
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onTreeFolderChanged() {
+  // Commented by KD
+  DvDirModelNode *node = m_folderTreeView->getCurrentNode();
+  //if (node)
+  //  node->visualizeContent(this);
+  //else
+  //  setFolder(TFilePath());
+  m_itemViewer->resetVerticalScrollBar();
+  m_itemViewer->updateContentSize();
+  m_itemViewer->getPanel()->update();
+  m_frameCountReader.stopReading();
+  IconGenerator::instance()->clearRequests();
+
+  DvDirModelFileFolderNode *fileFolderNode =
+      dynamic_cast<DvDirModelFileFolderNode *>(node);
+  if (fileFolderNode) emit treeFolderChanged(fileFolderNode->getPath());
+
+  // Restore scroll position
+  m_itemViewer->verticalScrollBar()->setValue(m_currentScroll);
+
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::changeFolder(const QModelIndex &index) {}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onDataChanged(const QModelIndex &topLeft,
+                                const QModelIndex &bottomRight) {
+  onTreeFolderChanged();
+}
+
+//-----------------------------------------------------------------------------
+
+bool SceneBrowser::acceptDrop(const QMimeData *data) const {
+  // se il browser non sta visualizzando un folder standard non posso accettare
+  // nessun drop
+  if (getFolder() == TFilePath()) return false;
+
+  if (data->hasFormat("application/vnd.toonz.levels") ||
+      data->hasFormat("application/vnd.toonz.currentscene") ||
+      data->hasFormat("application/vnd.toonz.drawings") ||
+      acceptResourceDrop(data->urls()))
+    return true;
+
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool SceneBrowser::drop(const QMimeData *mimeData) {
+  // se il browser non sta visualizzando un folder standard non posso accettare
+  // nessun drop
+  TFilePath folderPath = getFolder();
+  if (folderPath == TFilePath()) return false;
+
+  if (mimeData->hasFormat(CastItems::getMimeFormat())) {
+    const CastItems *items = dynamic_cast<const CastItems *>(mimeData);
+    if (!items) return false;
+
+    int i;
+    for (i = 0; i < items->getItemCount(); i++) {
+      CastItem *item = items->getItem(i);
+      if (TXshSimpleLevel *sl = item->getSimpleLevel()) {
+        TFilePath levelPath = sl->getPath().withParentDir(getFolder());
+        IoCmd::saveLevel(levelPath, sl, false);
+      } else if (TXshSoundLevel *level = item->getSoundLevel()) {
+        TFilePath soundPath = level->getPath().withParentDir(getFolder());
+        IoCmd::saveSound(soundPath, level, false);
+      }
+    }
+    refreshFolder(getFolder());
+    return true;
+  } else if (mimeData->hasFormat("application/vnd.toonz.currentscene")) {
+    TFilePath scenePath;
+    ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+    if (scene->isUntitled()) {
+      bool ok;
+      QString sceneName =
+          QInputDialog::getText(this, tr("Save Scene"), tr("Scene name:"),
+                                QLineEdit::Normal, QString(), &ok);
+      if (!ok || sceneName == "") return false;
+      scenePath = folderPath + sceneName.toStdWString();
+    } else
+      scenePath = folderPath + scene->getSceneName();
+    return IoCmd::saveScene(scenePath, false);
+  } else if (mimeData->hasFormat("application/vnd.toonz.drawings")) {
+    TFilmstripSelection *s =
+        dynamic_cast<TFilmstripSelection *>(TSelection::getCurrent());
+    if (!s) return false;
+    TXshSimpleLevel *sl = TApp::instance()->getCurrentLevel()->getSimpleLevel();
+    if (!sl) return false;
+
+    std::wstring levelName = sl->getName();
+    folderPath +=
+        TFilePath(levelName + ::to_wstring(sl->getPath().getDottedType()));
+    if (TSystem::doesExistFileOrLevel(folderPath)) {
+      QString question = "Level " + toQString(folderPath) +
+                         " already exists\nDo you want to duplicate it?";
+      int ret = DVGui::MsgBox(question, QObject::tr("Duplicate"),
+                              QObject::tr("Don't Duplicate"), 0);
+      if (ret == 2 || ret == 0) return false;
+      TFilePath path = folderPath;
+      NameBuilder *nameBuilder =
+          NameBuilder::getBuilder(::to_wstring(path.getName()));
+      do
+        levelName = nameBuilder->getNext();
+      while (TSystem::doesExistFileOrLevel(path.withName(levelName)));
+      folderPath = path.withName(levelName);
+    }
+    assert(!TSystem::doesExistFileOrLevel(folderPath));
+
+    TXshSimpleLevel *newSl = new TXshSimpleLevel();
+    newSl->setType(sl->getType());
+    newSl->clonePropertiesFrom(sl);
+    newSl->setName(levelName);
+    newSl->setPalette(sl->getPalette());
+    newSl->setScene(sl->getScene());
+    std::set<TFrameId> frames = s->getSelectedFids();
+    for (auto const &fid : frames) {
+      newSl->setFrame(fid, sl->getFrame(fid, false));
+    }
+
+    IoCmd::saveLevel(folderPath, newSl, false);
+    refreshFolder(folderPath.getParentDir());
+    return true;
+  } else if (mimeData->hasUrls()) {
+    int count = 0;
+    for (const QUrl &url : mimeData->urls()) {
+      TFilePath srcFp(url.toLocalFile().toStdWString());
+      TFilePath dstFp = srcFp.withParentDir(folderPath);
+      if (dstFp != srcFp) {
+        if (!TSystem::copyFileOrLevel(dstFp, srcFp))
+          DVGui::error(tr("There was an error copying %1 to %2")
+                           .arg(toQString(srcFp))
+                           .arg(toQString(dstFp)));
+      }
+    }
+    refreshFolder(folderPath);
+    return true;
+  } else
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::loadResources() {
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+
+  std::vector<TFilePath> filePaths;
+  fs->getSelectedFiles(filePaths);
+
+  if (filePaths.empty()) return;
+
+  IoCmd::LoadResourceArguments args;
+  args.resourceDatas.assign(filePaths.begin(), filePaths.end());
+
+  IoCmd::loadResources(args);
+}
+
+//-----------------------------------------------------------------------------
+
+namespace {
+
+bool parsePathName(const QString &fullpath, QString &parentPath, QString &name,
+                   QString &format) {
+  int index = fullpath.lastIndexOf('\\');
+  if (index == -1) index = fullpath.lastIndexOf('/');
+
+  QString filename;
+
+  if (index != -1) {
+    parentPath = fullpath.left(index + 1);
+    filename   = fullpath.right(fullpath.size() - index - 1);
+  } else {
+    parentPath = "";
+    filename   = fullpath;
+  }
+
+  index = filename.lastIndexOf('.');
+
+  if (index <= 0) return false;
+
+  format = filename.right(filename.size() - index - 1);
+  if (format == "") return false;
+
+  index--;
+  if (!filename.at(index).isDigit()) return false;
+
+  while (index >= 0 && filename.at(index).isDigit()) index--;
+
+  if (index < 0) return false;
+
+  name = filename.left(index + 1);
+
+  return true;
+}
+
+//---------------------------------------------------------
+
+void getLevelFiles(const QString &parentPath, const QString &name,
+                   const QString &format, QStringList &pathIn) {
+  QString dummy, dummy1, filter = "*." + format;
+  QDir dir(parentPath, filter);
+  QStringList list = dir.entryList();
+
+  for (int i = 0; i < list.size(); i++) {
+    QString item = list.at(i);
+    QString itemName;
+    if (!parsePathName(item, dummy, itemName, dummy1) || name != itemName)
+      continue;
+
+    pathIn.push_back(item);
+  }
+}
+
+//---------------------------------------------------------
+
+QString getFrame(const QString &filename) {
+  int index = filename.lastIndexOf('.');
+
+  if (index <= 0) return "";
+
+  index--;
+  if (!filename.at(index).isDigit()) return "";
+
+  int to, from;
+  to = from = index;
+  while (from >= 0 && filename.at(from).isDigit()) from--;
+
+  if (from < 0) return "";
+
+  char padStr[5];
+  padStr[4] = '\0';
+
+  int i, frame = 0;
+
+  QString number = filename.mid(from + 1, to - from);
+  for (i = 0; i < 4 - number.size(); i++) padStr[i] = '0';
+  for (i = 0; i < number.size(); i++)
+#if QT_VERSION >= 0x050500
+    padStr[4 - number.size() + i] = number.at(i).toLatin1();
+#else
+    padStr[4 - number.size() + i] = number.at(i).toAscii();
+#endif
+  return QString(padStr);
+}
+
+//------------------------------------------------------------------
+
+//-----------------------------------------------------------
+
+void renameSingleFileOrToonzLevel(const QString &fullpath) {
+  TFilePath fpin(fullpath.toStdString());
+
+  RenameAsToonzPopup popup(
+      QString::fromStdWString(fpin.withoutParentDir().getWideString()));
+  if (popup.exec() != QDialog::Accepted) return;
+
+  std::string name = popup.getName().toStdString();
+
+  if (name == fpin.getName()) {
+    DVGui::error(QString(
+        QObject::tr("The specified name is already assigned to the %1 file.")
+            .arg(fullpath)));
+    return;
+  }
+
+  if (popup.doOverwrite())
+    TSystem::renameFileOrLevel(fpin.withName(name), fpin, true);
+  else
+    TSystem::copyFileOrLevel(fpin.withName(name), fpin);
+}
+
+//----------------------------------------------------------
+
+void doRenameAsToonzLevel(const QString &fullpath) {
+  QString parentPath, name, format;
+
+  if (!parsePathName(fullpath, parentPath, name, format)) {
+    renameSingleFileOrToonzLevel(fullpath);
+    return;
+  }
+
+  QStringList pathIn;
+
+  getLevelFiles(parentPath, name, format, pathIn);
+
+  if (pathIn.empty()) return;
+
+  while (name.endsWith('_') || name.endsWith('.') || name.endsWith(' '))
+    name.chop(1);
+
+  RenameAsToonzPopup popup(name, pathIn.size());
+  if (popup.exec() != QDialog::Accepted) return;
+
+  name = popup.getName();
+
+  QString levelOutStr = parentPath + "/" + name + ".." + format;
+
+  TFilePath levelOut(levelOutStr.toStdWString());
+  if (TSystem::doesExistFileOrLevel(levelOut)) {
+    QApplication::restoreOverrideCursor();
+    int ret = DVGui::MsgBox(
+        QObject::tr("Warning: level %1 already exists; overwrite?")
+            .arg(toQString(levelOut)),
+        QObject::tr("Yes"), QObject::tr("No"), 1);
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+    if (ret == 2 || ret == 0) return;
+    TSystem::removeFileOrLevel(levelOut);
+  }
+
+  int i;
+  for (i = 0; i < pathIn.size(); i++) {
+    QString padStr = getFrame(pathIn[i]);
+    if (padStr == "") continue;
+    QString pathOut = parentPath + "/" + name + "." + padStr + "." + format;
+
+    if (popup.doOverwrite()) {
+      if (!QFile::rename(parentPath + "/" + pathIn[i], pathOut)) {
+        QString tmp(parentPath + "/" + pathIn[i]);
+        DVGui::error(QString(
+            QObject::tr("It is not possible to rename the %1 file.").arg(tmp)));
+        return;
+      }
+    } else if (!QFile::copy(parentPath + "/" + pathIn[i], pathOut)) {
+      QString tmp(parentPath + "/" + pathIn[i]);
+      DVGui::error(QString(
+          QObject::tr("It is not possible to copy the %1 file.").arg(tmp)));
+
+      return;
+    }
+  }
+}
+
+}  // namespace
+
+//-------------------------------------------------------------------------------
+
+void SceneBrowser::renameAsToonzLevel() {
+  std::vector<TFilePath> filePaths;
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  fs->getSelectedFiles(filePaths);
+  if (filePaths.size() != 1) return;
+
+  doRenameAsToonzLevel(QString::fromStdWString(filePaths[0].getWideString()));
+
+  QApplication::restoreOverrideCursor();
+
+  FileBrowser::refreshFolder(filePaths[0].getParentDir());
+}
+
+#ifdef LEVO
+
+void SceneBrowser::convertToUnpaintedTlv() {
+  std::vector<TFilePath> filePaths;
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  fs->getSelectedFiles(filePaths);
+
+  QStringList sl;
+  sl << "Apply Autoclose                        "
+     << "Don't Apply Autoclose                          ";
+  bool ok;
+  QString autoclose = QInputDialog::getItem(
+      this, tr("Convert To Unpainted Tlv"), "", sl, 0, false, &ok);
+  if (!ok) return;
+
+  QApplication::setOverrideCursor(Qt::WaitCursor);
+
+  int i, totFrames = 0;
+  std::vector<Convert2Tlv *> converters;
+  for (i = 0; i < filePaths.size(); i++) {
+    Convert2Tlv *converter =
+        new Convert2Tlv(filePaths[i], TFilePath(), TFilePath(), -1, -1,
+                        autoclose == sl.at(0), TFilePath(), 0, 0, 0);
+
+    if (TSystem::doesExistFileOrLevel(converter->m_levelOut)) {
+      QApplication::restoreOverrideCursor();
+      int ret = DVGui::MsgBox(tr("Warning: level %1 already exists; overwrite?")
+                                  .arg(toQString(converter->m_levelOut)),
+                              tr("Yes"), tr("No"), 1);
+      QApplication::setOverrideCursor(Qt::WaitCursor);
+      if (ret == 2 || ret == 0) {
+        delete converter;
+        continue;
+      }
+      TSystem::removeFileOrLevel(converter->m_levelOut);
+    }
+
+    totFrames += converter->getFramesToConvertCount();
+    converters.push_back(converter);
+  }
+
+  if (converters.empty()) {
+    QApplication::restoreOverrideCursor();
+    return;
+  }
+
+  ProgressDialog pb("", "Cancel", 0, totFrames);
+  int j, l, k = 0;
+  for (i = 0; i < converters.size(); i++) {
+    std::string errorMessage;
+    if (!converters[i]->init(errorMessage)) {
+      converters[i]->abort();
+      DVGui::error(QString::fromStdString(errorMessage));
+      delete converters[i];
+      converters[i] = 0;
+      continue;
+    }
+
+    int count = converters[i]->getFramesToConvertCount();
+
+    pb.setLabelText("Generating level " + toQString(converters[i]->m_levelOut));
+    pb.show();
+
+    for (j = 0; j < count; j++) {
+      std::string errorMessage = "";
+      if (!converters[i]->convertNext(errorMessage) || pb.wasCanceled()) {
+        for (l = i; l < converters.size(); l++) {
+          converters[l]->abort();
+          delete converters[i];
+          converters[i] = 0;
+        }
+        if (errorMessage != "")
+          DVGui::error(QString::fromStdString(errorMessage));
+        QApplication::restoreOverrideCursor();
+        SceneBrowser::refreshFolder(filePaths[0].getParentDir());
+        return;
+      }
+      pb.setValue(++k);
+    }
+    TFilePath levelOut(converters[i]->m_levelOut);
+    delete converters[i];
+    IconGenerator::instance()->invalidate(levelOut);
+
+    converters[i] = 0;
+  }
+
+  QApplication::restoreOverrideCursor();
+  pb.hide();
+  DVGui::info(tr("Done: All Levels  converted to TLV Format"));
+
+  SceneBrowser::refreshFolder(filePaths[0].getParentDir());
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::convertToPaintedTlv() {
+  std::vector<TFilePath> filePaths;
+  FileSelection *fs =
+      dynamic_cast<FileSelection *>(m_itemViewer->getPanel()->getSelection());
+  if (!fs) return;
+  fs->getSelectedFiles(filePaths);
+
+  if (filePaths.size() != 2) return;
+
+  QStringList sl;
+  sl << "Apply Autoclose                      "
+     << "Don't Apply Autoclose                        ";
+  bool ok;
+  QString autoclose = QInputDialog::getItem(this, tr("Convert To Painted Tlv"),
+                                            "", sl, 0, false, &ok);
+  if (!ok) return;
+
+  QApplication::setOverrideCursor(Qt::WaitCursor);
+
+  Convert2Tlv *converter =
+      new Convert2Tlv(filePaths[0], filePaths[1], TFilePath(), -1, -1,
+                      autoclose == sl.at(0), TFilePath(), 0, 0, 0);
+
+  if (TSystem::doesExistFileOrLevel(converter->m_levelOut)) {
+    QApplication::restoreOverrideCursor();
+    int ret = DVGui::MsgBox(tr("Warning: level %1 already exists; overwrite?")
+                                .arg(toQString(converter->m_levelOut)),
+                            tr("Yes"), tr("No"), 1);
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+    if (ret == 2 || ret == 0) {
+      QApplication::restoreOverrideCursor();
+      return;
+    }
+    TSystem::removeFileOrLevel(converter->m_levelOut);
+  }
+
+  std::string errorMessage;
+  if (!converter->init(errorMessage)) {
+    converter->abort();
+    delete converter;
+    DVGui::error(QString::fromStdString(errorMessage));
+    QApplication::restoreOverrideCursor();
+    return;
+  }
+  int count = converter->getFramesToConvertCount();
+
+  ProgressDialog pb("Generating level " + toQString(converter->m_levelOut),
+                    "Cancel", 0, count);
+  pb.show();
+
+  for (int i = 0; i < count; i++) {
+    errorMessage = "";
+    if (!converter->convertNext(errorMessage) || pb.wasCanceled()) {
+      converter->abort();
+      delete converter;
+      if (errorMessage != "")
+        DVGui::error(QString::fromStdString(errorMessage));
+      QApplication::restoreOverrideCursor();
+      SceneBrowser::refreshFolder(filePaths[0].getParentDir());
+      return;
+    }
+
+    pb.setValue(i + 1);
+  }
+
+  TFilePath levelOut(converter->m_levelOut);
+  delete converter;
+  IconGenerator::instance()->invalidate(levelOut);
+
+  QApplication::restoreOverrideCursor();
+  pb.hide();
+  DVGui::info(tr("Done: 2 Levels  converted to TLV Format"));
+
+  fs->selectNone();
+  SceneBrowser::refreshFolder(filePaths[0].getParentDir());
+}
+#endif
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onSceneSwitched() {
+  ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+  TFilePath scenesFolder = scene->getScenePath().getParentDir();
+  //TFilePath scenesFolder = TProjectManager::instance()->getCurrentProject()->getScenesPath();
+  setFolder(scenesFolder, true);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onSelectedItems(const std::set<int> &indexes) {
+  std::set<TFilePath> filePaths;
+  std::set<int>::const_iterator it;
+
+  // pass the frameId list for reuse
+  std::list<std::vector<TFrameId>> frameIDs;
+
+  if (indexes.empty()) {  // inform selection is released
+    emit filePathsSelected(filePaths, frameIDs);
+    return;
+  }
+
+  for (it = indexes.begin(); it != indexes.end(); ++it) {
+    filePaths.insert(m_items[*it].m_path);
+    frameIDs.insert(frameIDs.begin(), m_items[*it].m_frameIds);
+  }
+
+  // reuse the list of TFrameId in order to skip loadInfo() when loading the
+  // level with sequencial frames.
+  emit filePathsSelected(filePaths, frameIDs);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onClickedItem(int index) {
+  if (0 <= index && index < (int)m_items.size()) {
+    // if the folder is clicked, then move the current folder
+    TFilePath fp = m_items[index].m_path;
+    if (m_items[index].m_isFolder) {
+      setFolder(fp, true);
+      QModelIndex index = m_folderTreeView->currentIndex();
+      if (index.isValid()) m_folderTreeView->scrollTo(index);
+    } else
+      emit filePathClicked(fp);
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::onDoubleClickedItem(int index) {
+  // TODO: Avoid duplicate code with onClickedItem().
+  if (0 <= index && index < (int)m_items.size()) {
+    // if the folder is clicked, then move the current folder
+    TFilePath fp = m_items[index].m_path;
+    if (m_items[index].m_isFolder) {
+      setFolder(fp, true);
+      QModelIndex index = m_folderTreeView->currentIndex();
+      if (index.isValid()) m_folderTreeView->scrollTo(index);
+    } else
+      emit filePathDoubleClicked(fp);
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::refreshFolder(const TFilePath &folderPath) {
+  std::set<SceneBrowser *>::iterator it;
+  for (it = activePreproductionBoards.begin(); it != activePreproductionBoards.end(); ++it) {
+    SceneBrowser *browser = *it;
+    DvDirModel::instance()->refreshFolder(folderPath);
+    if (browser->getFolder() == folderPath) {
+      browser->setFolder(folderPath, false, true);
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::updateItemViewerPanel() {
+  std::set<SceneBrowser *>::iterator it;
+  for (it = activePreproductionBoards.begin(); it != activePreproductionBoards.end(); ++it) {
+    SceneBrowser *browser = *it;
+    browser->m_itemViewer->getPanel()->update();
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::getExpandedFolders(DvDirModelNode *node,
+                                     QList<DvDirModelNode *> &expandedNodes) {
+  if (!node) return;
+  QModelIndex newIndex = DvDirModel::instance()->getIndexByNode(node);
+  if (!m_folderTreeView->isExpanded(newIndex)) return;
+  expandedNodes.push_back(node);
+
+  int i = 0;
+  for (i = 0; i < node->getChildCount(); i++)
+    getExpandedFolders(node->getChild(i), expandedNodes);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::refresh() {
+  TFilePath originalFolder(
+      m_folder);  // setFolder is invoked by Qt throughout the following...
+
+  int dx                   = m_folderTreeView->verticalScrollBar()->value();
+  DvDirModelNode *rootNode = DvDirModel::instance()->getNode(QModelIndex());
+
+  QModelIndex index = DvDirModel::instance()->getIndexByNode(rootNode);
+
+  bool vcEnabled = m_folderTreeView->refreshVersionControlEnabled();
+
+  m_folderTreeView->setRefreshVersionControlEnabled(false);
+  DvDirModel::instance()->refreshFolderChild(index);
+  m_folderTreeView->setRefreshVersionControlEnabled(vcEnabled);
+
+  QList<DvDirModelNode *> expandedNodes;
+  int i;
+  for (i = 0; i < rootNode->getChildCount(); i++)
+    getExpandedFolders(rootNode->getChild(i), expandedNodes);
+
+  for (i = 0; i < expandedNodes.size(); i++) {
+    DvDirModelNode *node = expandedNodes[i];
+    if (!node || !node->hasChildren()) continue;
+    QModelIndex ind = DvDirModel::instance()->getIndexByNode(node);
+    if (!ind.isValid()) continue;
+    m_folderTreeView->expand(ind);
+  }
+  m_folderTreeView->verticalScrollBar()->setValue(dx);
+
+  setFolder(originalFolder, false, true);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::newScene() {
+
+  m_currentScroll = m_itemViewer->verticalScrollBar()->value();
+
+  TFilePath parentFolder = getFolder();
+  QString sceneName;
+  TFilePath scenePath;
+  ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+  if (scene->isUntitled()) {
+      bool ok;
+      sceneName =
+          QInputDialog::getText(this, tr("Save Scene"), tr("Scene name:"),
+                                QLineEdit::Normal, QString(), &ok);
+      if (!ok || sceneName == "") return;
+    } else {
+      sceneName = QString::fromWCharArray( scene->getSceneName().c_str() );
+  }
+  QString prefix;
+  QString number;
+  for(int j = 0; j<sceneName.length(); j++) {
+    QChar c;
+    c = sceneName.at(sceneName.length()-1-j);
+    if (c.isDigit()) {
+      number = QString(c) + number;
+    } else {
+      prefix = sceneName;
+      prefix.truncate(sceneName.length()-j);
+      break;
+    }
+  }
+  if (number.length()==0) {
+    //prefix+="-";
+    number="000";
+  }
+  int i = number.toInt();
+  do {
+    QString number_ext = QStringLiteral("%1").arg(++i, number.length(), 10, QLatin1Char('0'));
+    scenePath = parentFolder + (prefix.toStdWString()+number_ext.toStdWString()+L".tnz");
+  } while (TFileStatus(scenePath).doesExist());
+  
+  if (!IoCmd::saveSceneIfNeeded(QObject::tr("Change project"))) return;
+  IoCmd::newScene();
+  IoCmd::saveScene(scenePath, false);
+  return;
+
+  if (parentFolder == TFilePath() || !TFileStatus(parentFolder).isDirectory())
+    return;
+  QString tempName(tr("New Folder"));
+  std::wstring folderName = tempName.toStdWString();
+  TFilePath folderPath    = parentFolder + folderName;
+  //int i                   = 1;
+  while (TFileStatus(folderPath).doesExist())
+    folderPath = parentFolder + (folderName + L" " + std::to_wstring(++i));
+
+  try {
+    TSystem::mkDir(folderPath);
+
+  } catch (...) {
+    DVGui::error(tr("It is not possible to create the %1 folder.")
+                     .arg(toQString(folderPath)));
+    return;
+  }
+
+  DvDirModel *model = DvDirModel::instance();
+
+  QModelIndex parentFolderIndex = m_folderTreeView->currentIndex();
+  model->refresh(parentFolderIndex);
+  m_folderTreeView->expand(parentFolderIndex);
+
+  std::wstring newFolderName = folderPath.getWideName();
+  QModelIndex newFolderIndex =
+      model->childByName(parentFolderIndex, newFolderName);
+  if (newFolderIndex.isValid()) {
+    m_folderTreeView->setCurrentIndex(newFolderIndex);
+    m_folderTreeView->scrollTo(newFolderIndex);
+    m_folderTreeView->QAbstractItemView::edit(newFolderIndex);
+  }
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::showEvent(QShowEvent *) {
+  activePreproductionBoards.insert(this);
+  // refresh
+  if (getFolder() != TFilePath())
+    setFolder(getFolder(), false, true);
+  else if (getDayDateString() != "")
+    setHistoryDay(getDayDateString());
+  m_folderTreeView->scrollTo(m_folderTreeView->currentIndex());
+
+  // Refresh SVN
+  DvDirVersionControlNode *vcNode = dynamic_cast<DvDirVersionControlNode *>(
+      m_folderTreeView->getCurrentNode());
+  if (vcNode) m_folderTreeView->refreshVersionControl(vcNode);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::hideEvent(QHideEvent *) {
+  activePreproductionBoards.erase(this);
+  m_itemViewer->getPanel()->getItemViewPlayDelegate()->resetPlayWidget();
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::makeCurrentProjectVisible() {}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::enableGlobalSelection(bool enabled) {
+  m_folderTreeView->enableGlobalSelection(enabled);
+  m_itemViewer->enableGlobalSelection(enabled);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::selectNone() { m_itemViewer->selectNone(); }
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::enableDoubleClickToOpenScenes() {
+  // perhaps this should disconnect existing signal handlers first
+  connect(this, SIGNAL(filePathDoubleClicked(const TFilePath &)), this,
+          SLOT(tryToOpenScene(const TFilePath &)));
+}
+
+void SceneBrowser::enableSingleClickToOpenScenes() {
+  // perhaps this should disconnect existing signal handlers first
+  connect(this, SIGNAL(filePathClicked(const TFilePath &)), this,
+          SLOT(tryToOpenScene(const TFilePath &)));
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneBrowser::tryToOpenScene(const TFilePath &filePath) {
+  if (filePath.getType() == "tnz") {
+    IoCmd::loadScene(filePath);
+  }
+}
+
+//=============================================================================
+
+OpenFloatingPanel openPreproductionBoardPane(MI_OpenPreproductionBoard, "PreproductionBoard",
+                                  QObject::tr("Preproduction Board"));
diff --git a/toonz/sources/toonz/scenebrowser.h b/toonz/sources/toonz/scenebrowser.h
new file mode 100644
index 0000000..5a4edb0
--- /dev/null
+++ b/toonz/sources/toonz/scenebrowser.h
@@ -0,0 +1,265 @@
+#pragma once
+
+#ifndef SCENEBROWSER_INCLUDED
+#define SCENEBROWSER_INCLUDED
+
+#include <QFrame>
+#include <QTreeWidget>
+#include <QDateTime>
+#include <QItemDelegate>
+#include <QCheckBox>
+#include <QList>
+#include <QModelIndex>
+#include "dvitemview.h"
+#include "tfilepath.h"
+#include "toonzqt/dvdialog.h"
+#include "versioncontrol.h"
+#include "filebrowser.h"
+
+#include "tthread.h"
+
+class QLineEdit;
+class QTreeWidgetItem;
+class QSplitter;
+class DvDirModelNode;
+class DvDirTreeView;
+class QFileSystemWatcher;
+
+//-----------------------------------------------------------------------------
+class SceneBrowserButtonBar final : public QToolBar {
+  Q_OBJECT
+  QAction *m_folderBack;
+  QAction *m_folderFwd;
+
+public:
+  SceneBrowserButtonBar(DvItemViewer *itemViewer, QWidget *parent = 0);
+
+signals:
+  void newScene();
+};
+//-----------------------------------------------------------------------------
+
+class SceneBrowser final : public QFrame, public DvItemListModel {
+  Q_OBJECT
+
+public:
+#if QT_VERSION >= 0x050500
+  SceneBrowser(QWidget *parent, Qt::WindowFlags flags = 0,
+              bool noContextMenu = false, bool multiSelectionEnabled = false);
+#else
+  SceneBrowser(QWidget *parent, Qt::WFlags flags = 0, bool noContextMenu = false,
+              bool multiSelectionEnabled = false);
+#endif
+  ~SceneBrowser();
+
+  void sortByDataModel(DataType dataType, bool isDiscendent) override;
+  void refreshData() override;
+
+  int getItemCount() const override;
+  QVariant getItemData(int index, DataType dataType,
+                       bool isSelected = false) override;
+
+  bool canRenameItem(int index) const override;
+  void renameItem(int index, const QString &newName) override;
+
+  bool isSceneItem(int index) const override;
+  void startDragDrop() override;
+  QMenu *getContextMenu(QWidget *parent, int index) override;
+
+  /*!
+This functions adds to the types to be filtered a new type;
+if this function is never  called, the default filter is all image
+files and scene files and palette files
+*/
+  void addFilterType(const QString &type);
+
+  /*!
+The setFilterTypes function directly specifies the list of file
+types to be displayed in the file browser.
+*/
+  void setFilterTypes(const QStringList &types);
+  const QStringList &getFilterTypes() const { return m_filter; }
+  void removeFilterType(const QString &type);
+
+  void setFolder(const TFilePath &fp, bool expandNode = false,
+                 bool forceUpdate = false);
+  // process when inputting the folder which is not regitered in the folder tree
+  // (e.g. UNC path in Windows)
+  void setUnregisteredFolder(const TFilePath &fp);
+
+  void setHistoryDay(std::string dayDateString);
+
+  TFilePath getFolder() const { return m_folder; }
+  std::string getDayDateString() const { return m_dayDateString; }
+
+  static void refreshFolder(const TFilePath &folder);
+
+  static void updateItemViewerPanel();
+
+  // ritorna true se il file e' stato rinominato. dopo la chiamata fp contiene
+  // il nuovo path
+  static bool renameFile(TFilePath &fp, QString newName);
+
+  void makeCurrentProjectVisible();
+
+  void enableGlobalSelection(bool enabled);
+  void selectNone();
+
+  QSplitter *getMainSplitter() const { return m_mainSplitter; }
+
+  // Enable double-click to open a scene.
+  // This is not always desirable (e.g. if a user double-clicks on a file in
+  // a "Save As" dialog, they expect the file will be saved to, not opened).
+  // So it is disabled by default.
+  void enableDoubleClickToOpenScenes();
+
+  void enableSingleClickToOpenScenes();
+
+protected:
+  int findIndexWithPath(TFilePath path);
+  void getExpandedFolders(DvDirModelNode *node,
+                          QList<DvDirModelNode *> &expandedNodes);
+
+  bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data,
+                    Qt::DropAction action);
+
+  bool acceptDrop(const QMimeData *data) const override;
+  bool drop(const QMimeData *data) override;
+  void showEvent(QShowEvent *) override;
+  void hideEvent(QHideEvent *) override;
+
+  // Fill the QStringList with files selected in the browser, auxiliary files
+  // (palette for tlv, hooks, sceneIcons)
+  // retrieve also the path, and return also the sceneIconsCount
+  void setupVersionControlCommand(QStringList &files, QString &path,
+                                  int &sceneIconsCount);
+  void setupVersionControlCommand(QString &file, QString &path);
+
+  void refreshHistoryButtons();
+
+public slots:
+
+  void onTreeFolderChanged();
+
+protected slots:
+
+  void refresh();
+
+  void changeFolder(const QModelIndex &index);
+  void onDataChanged(const QModelIndex &topLeft,
+                     const QModelIndex &bottomRight);
+  void loadResources();
+  void onClickedItem(int index);
+  void onDoubleClickedItem(int index);
+  void onSelectedItems(const std::set<int> &indexes);
+  void onSceneSwitched();
+  void newScene();
+
+  void onBackButtonPushed();
+  void onFwdButtonPushed();
+  void onFolderEdited();
+  void storeFolderHistory();
+  void clearHistory();
+
+  void renameAsToonzLevel();
+  void updateAndEditVersionControl();
+  void editVersionControl();
+  void unlockVersionControl();
+
+  void editFrameRangeVersionControl();
+  void unlockFrameRangeVersionControl();
+
+  void putFrameRangeVersionControl();
+  void revertFrameRangeVersionControl();
+
+  void showLockInformation();
+  void showFrameRangeLockInfo();
+
+  void putVersionControl();
+  void revertVersionControl();
+  void deleteVersionControl();
+  void getVersionControl();
+  void getRevisionVersionControl();
+  void getRevisionHistory();
+
+  void onVersionControlCommandDone(const QStringList &files);
+
+  void onFileSystemChanged(const QString &folderPath);
+
+  // If filePath is a valid scene file, open it. Otherwise do nothing.
+  void tryToOpenScene(const TFilePath &filePath);
+
+signals:
+
+  void filePathClicked(const TFilePath &);
+  void filePathDoubleClicked(const TFilePath &);
+  // reuse the list of TFrameId in order to skip loadInfo() when loading the
+  // level with sequencial frames.
+  void filePathsSelected(const std::set<TFilePath> &,
+                         const std::list<std::vector<TFrameId>> &);
+  void treeFolderChanged(const TFilePath &);
+
+  // for activating/deactivating the folder history buttons( back button &
+  // forward button )
+  void historyChanged(bool, bool);
+
+private:
+  struct Item {
+    QString m_name;
+    qlonglong m_fileSize;
+    QDateTime m_creationDate;
+    QDateTime m_modifiedDate;
+    int m_frameCount;
+    QString m_fileType;
+    TFilePath m_path;
+    bool m_validInfo;
+
+    bool m_isFolder;
+    bool m_isLink;
+    // calling loadInfo to the level with sequencial frames is time consuming.
+    // so keep the list of frameIds at the first time and try to reuse it.
+    std::vector<TFrameId> m_frameIds;
+
+    Item() : m_frameCount(0), m_validInfo(false), m_fileSize(0) {}
+    Item(const TFilePath &path, bool folder = false, bool link = false,
+         QString name = QString(""))
+        : m_path(path)
+        , m_frameCount(0)
+        , m_validInfo(false)
+        , m_fileSize(0)
+        , m_isFolder(folder)
+        , m_isLink(link)
+        , m_name(name) {}
+  };
+
+private:
+  DvDirTreeView *m_folderTreeView;
+  QSplitter *m_mainSplitter;
+  QLineEdit *m_folderName;
+  DvItemViewer *m_itemViewer;
+  FrameCountReader m_frameCountReader;
+
+  // folder history
+  QList<QModelIndex> m_indexHistoryList;
+  int m_currentPosition;
+  int m_currentScroll;
+
+  std::vector<Item> m_items;
+  TFilePath m_folder;
+  std::string m_dayDateString;
+  QStringList m_filter;
+  std::map<TFilePath, Item> m_multiFileItemMap;
+
+private:
+  void readFrameCount(Item &item);
+  void readInfo(Item &item);
+
+  void refreshCurrentFolderItems();
+
+  DvItemListModel::Status getItemVersionControlStatus(
+      const SceneBrowser::Item &item);
+};
+
+//-----------------------------------------------------------
+
+#endif
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);
+}
+
+//-----------------------------------------------------------------------------
diff --git a/toonz/sources/toonz/tpanels.cpp b/toonz/sources/toonz/tpanels.cpp
index 70d1082..f3e677b 100644
--- a/toonz/sources/toonz/tpanels.cpp
+++ b/toonz/sources/toonz/tpanels.cpp
@@ -18,6 +18,7 @@
 #include "flipbook.h"
 #include "castviewer.h"
 #include "filebrowser.h"
+#include "scenebrowser.h"
 #include "filmstrip.h"
 #include "previewfxmanager.h"
 #include "comboviewerpane.h"
@@ -1208,6 +1209,23 @@ public:
 } browserFactory;
 
 //=============================================================================
+// PreproductionBoardFactory
+//-----------------------------------------------------------------------------
+class PreproductionBoardFactory final : public TPanelFactory {
+public:
+  PreproductionBoardFactory() : TPanelFactory("PreproductionBoard") {}
+  void initialize(TPanel *panel) override {
+    SceneBrowser *browser = new SceneBrowser(panel, 0, false, true);
+    panel->setWidget(browser);
+    panel->setWindowTitle(QObject::tr("Preproduction Board"));
+    TFilePath scenesFolder =
+        TProjectManager::instance()->getCurrentProject()->getScenesPath();
+    browser->setFolder(scenesFolder, true);
+    browser->enableSingleClickToOpenScenes();
+  }
+} PreproductionBoardFactory;
+
+//=============================================================================
 // CastViewerFactory
 //-----------------------------------------------------------------------------
 
diff --git a/toonz/sources/toonzqt/icongenerator.cpp b/toonz/sources/toonzqt/icongenerator.cpp
index d0c4c5e..fc9a039 100644
--- a/toonz/sources/toonzqt/icongenerator.cpp
+++ b/toonz/sources/toonzqt/icongenerator.cpp
@@ -1086,9 +1086,9 @@ Qt::transparent)
 
     bbox = (bbox * icon->getBounds())
                .enlarge(-1);  // Add a 1 pixel transparent margin - this
-    if (bbox.getLx() > 0 &&
-        bbox.getLy() > 0)  // way the actual content doesn't look trimmed.
-      ::makeChessBackground(icon->extract(bbox));
+    //if (bbox.getLx() > 0 &&
+    //    bbox.getLy() > 0)  // way the actual content doesn't look trimmed.
+    //  ::makeChessBackground(icon->extract(bbox));
   } else
     icon->fill(TPixel32(255, 0, 0));