Blob Blame History Raw


#include "exportscenepopup.h"

// Tnz6 includes
#include "tapp.h"
#include "filebrowser.h"
#include "iocommand.h"

// TnzQt includes
#include "toonzqt/gutil.h"

// TnzLib includes
#include "toonz/tproject.h"
#include "toonz/toonzscene.h"
#include "toonz/sceneresources.h"

// TnzCore includes
#include "tsystem.h"

// Qt includes
#include <QVBoxLayout>
#include <QLabel>
#include <QButtonGroup>
#include <QRadioButton>
#include <QPushButton>
#include <QHeaderView>
#include <QPainter>
#include <QApplication>
#include <QMainWindow>

using namespace DVGui;

//------------------------------------------------------------------------
namespace
{
//------------------------------------------------------------------------

TFilePath importScene(TFilePath scenePath)
{
	ToonzScene scene;
	bool ret;
	try {
		ret = IoCmd::loadScene(scene, scenePath, true);
	} catch (TException &e) {
		DVGui::error(QObject::tr("Error loading scene %1 :%2").arg(toQString(scenePath)).arg(QString::fromStdWString(e.getMessage())));

		return TFilePath();
	} catch (...) {
		DVGui::error(QObject::tr("Error loading scene %1").arg(toQString(scenePath)));
		return TFilePath();
	}

	if (!ret) {
		DVGui::error(QObject::tr("It is not possible to export the scene %1 because it does not belong to any project.").arg(toQString(scenePath)));

		return TFilePath();
	}

	TFilePath path = scene.getScenePath();
	scene.save(scene.getScenePath());
	DvDirModel::instance()->refreshFolder(TProjectManager::instance()->getCurrentProjectPath().getParentDir());
	return path;
}

//------------------------------------------------------------------------

int collectAssets(TFilePath scenePath)
{
	ToonzScene scene;
	scene.load(scenePath);
	ResourceCollector collector(&scene);
	SceneResources resources(&scene, scene.getXsheet());
	resources.accept(&collector);
	int count = collector.getCollectedResourceCount();
	if (count > 0) {
		scene.save(scenePath);
	}
	return count;
}

//------------------------------------------------------------------------
} //namespace
//------------------------------------------------------------------------

//=============================================================================
// MyDvDirModelFileFolderNode [File folder]

DvDirModelNode *ExportSceneDvDirModelFileFolderNode::makeChild(std::wstring name)
{
	return createExposeSceneNode(this, m_path + name);
}

//-----------------------------------------------------------------------------

DvDirModelFileFolderNode *ExportSceneDvDirModelFileFolderNode::createExposeSceneNode(DvDirModelNode *parent, const TFilePath &path)
{
	DvDirModelFileFolderNode *node;
	if (path.getType() == "tnz")
		return 0;
	else if (TProjectManager::instance()->isProject(path))
		node = new ExportSceneDvDirModelProjectNode(parent, path);
	else
		node = new ExportSceneDvDirModelFileFolderNode(parent, path);
	if (path.getName().find("_files") == std::string::npos)
		node->enableRename(true);
	return node;
}

//=============================================================================
// ExportSceneDvDirModelProjectNode

QPixmap ExportSceneDvDirModelProjectNode::getPixmap(bool isOpen) const
{
	static QPixmap openProjectPixmap(":Resources/browser_project_open.png");
	static QPixmap closeProjectPixmap(":Resources/browser_project_close.png");
	return isOpen ? openProjectPixmap : closeProjectPixmap;
}

//=============================================================================
// ExportSceneDvDirModelRootNode [Root]

ExportSceneDvDirModelRootNode::ExportSceneDvDirModelRootNode()
	: DvDirModelNode(0, L"Root")
{
	m_nodeType = "Root";
}

//-----------------------------------------------------------------------------

void ExportSceneDvDirModelRootNode::add(std::wstring name, const TFilePath &path)
{
	DvDirModelNode *child = new ExportSceneDvDirModelFileFolderNode(this, name, path);
	child->setRow((int)m_children.size());
	m_children.push_back(child);
}

//-----------------------------------------------------------------------------

void ExportSceneDvDirModelRootNode::refreshChildren()
{
	m_childrenValid = true;
	m_children.clear();
	//if(m_children.empty())
	//{
	TProjectManager *pm = TProjectManager::instance();
	std::vector<TFilePath> projectRoots;
	pm->getProjectRoots(projectRoots);

	int i;
	for (i = 0; i < (int)projectRoots.size(); i++) {
		TFilePath projectRoot = projectRoots[i];
		ExportSceneDvDirModelSpecialFileFolderNode *projectRootNode =
			new ExportSceneDvDirModelSpecialFileFolderNode(this, L"Project root", projectRoot);
		projectRootNode->setPixmap(QPixmap(":Resources/projects.png"));
		m_projectRootNodes.push_back(projectRootNode);
		addChild(projectRootNode);
	}

	TFilePath sandboxProjectPath = pm->getSandboxProjectFolder();
	m_sandboxProjectNode =
		new ExportSceneDvDirModelProjectNode(this, sandboxProjectPath);
	addChild(m_sandboxProjectNode);

	// SVN Repository
	QList<SVNRepository> repositories = VersionControl::instance()->getRepositories();
	int count = repositories.size();
	for (int i = 0; i < count; i++) {
		SVNRepository repo = repositories.at(i);

		ExportSceneDvDirModelSpecialFileFolderNode *node =
			new ExportSceneDvDirModelSpecialFileFolderNode(this, repo.m_name.toStdWString(), TFilePath(repo.m_localPath.toStdWString()));
		node->setPixmap(QPixmap(":Resources/vcroot.png"));
		addChild(node);
	}
	//}
}

//-----------------------------------------------------------------------------

DvDirModelNode *ExportSceneDvDirModelRootNode::getNodeByPath(const TFilePath &path)
{
	DvDirModelNode *node = 0;
	int i;
	//! path could be the sandbox project or in the sandbox project
	if (m_sandboxProjectNode && m_sandboxProjectNode->getPath() == path)
		return m_sandboxProjectNode;
	if (m_sandboxProjectNode) {
		for (i = 0; i < m_sandboxProjectNode->getChildCount(); i++) {
			DvDirModelNode *node = m_sandboxProjectNode->getChild(i)->getNodeByPath(path);
			if (node)
				return node;
		}
	}
	//! or it could be a different project, under some project root
	for (i = 0; i < (int)m_projectRootNodes.size(); i++) {
		node = m_projectRootNodes[i]->getNodeByPath(path);
		if (node)
			return node;
	}
	//! it could be a regular folder, somewhere in the file system

	return 0;
}

//=============================================================================
// ExportSceneDvDirModel

ExportSceneDvDirModel::ExportSceneDvDirModel()
{
	m_root = new ExportSceneDvDirModelRootNode();
	m_root->refreshChildren();
}

//-----------------------------------------------------------------------------

ExportSceneDvDirModel::~ExportSceneDvDirModel()
{
	delete m_root;
}

//-----------------------------------------------------------------------------

DvDirModelNode *ExportSceneDvDirModel::getNode(const QModelIndex &index) const
{
	if (index.isValid())
		return static_cast<DvDirModelNode *>(index.internalPointer());
	else
		return m_root;
}

//-----------------------------------------------------------------------------

QModelIndex ExportSceneDvDirModel::index(int row, int column, const QModelIndex &parent) const
{
	if (column != 0)
		return QModelIndex();
	DvDirModelNode *parentNode = m_root;
	if (parent.isValid())
		parentNode = getNode(parent);
	if (row < 0 || row >= parentNode->getChildCount())
		return QModelIndex();
	DvDirModelNode *node = parentNode->getChild(row);
	return createIndex(row, column, node);
}

//-----------------------------------------------------------------------------

QModelIndex ExportSceneDvDirModel::parent(const QModelIndex &index) const
{
	if (!index.isValid())
		return QModelIndex();
	DvDirModelNode *node = getNode(index);
	DvDirModelNode *parentNode = node->getParent();
	if (!parentNode || parentNode == m_root)
		return QModelIndex();
	else
		return createIndex(parentNode->getRow(), 0, parentNode);
}

//-----------------------------------------------------------------------------

QModelIndex ExportSceneDvDirModel::childByName(const QModelIndex &parent, const std::wstring &name) const
{
	if (!parent.isValid())
		return QModelIndex();
	DvDirModelNode *parentNode = getNode(parent);
	if (!parentNode)
		return QModelIndex();
	int row = parentNode->rowByName(name);
	if (row < 0 || row >= parentNode->getChildCount())
		return QModelIndex();
	DvDirModelNode *childNode = parentNode->getChild(row);
	return createIndex(row, 0, childNode);
}

//-----------------------------------------------------------------------------

int ExportSceneDvDirModel::rowCount(const QModelIndex &parent) const
{
	DvDirModelNode *node = getNode(parent);
	int childCount = node->getChildCount();
	return childCount;
}

//-----------------------------------------------------------------------------

QVariant ExportSceneDvDirModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();
	DvDirModelNode *node = getNode(index);
	if (role == Qt::DisplayRole || role == Qt::EditRole)
		return QString::fromStdWString(node->getName());
	else if (role == Qt::DecorationRole) {
		return QVariant();
	} else if (role == Qt::ForegroundRole) {
		if (!node || !node->isRenameEnabled())
			return QBrush(Qt::blue);
		else
			return QVariant();
	} else
		return QVariant();
}

//-----------------------------------------------------------------------------

Qt::ItemFlags ExportSceneDvDirModel::flags(const QModelIndex &index) const
{
	Qt::ItemFlags flags = QAbstractItemModel::flags(index);
	if (index.isValid()) {
		DvDirModelNode *node = getNode(index);
		if (node && node->isRenameEnabled())
			flags |= Qt::ItemIsEditable;
	}
	return flags;
}

//-----------------------------------------------------------------------------

bool ExportSceneDvDirModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
	if (!index.isValid())
		return false;
	DvDirModelNode *node = getNode(index);
	if (!node || !node->isRenameEnabled())
		return false;
	QString newName = value.toString();
	if (newName == "")
		return false;
	if (!node->setName(newName.toStdWString()))
		return false;
	emit dataChanged(index, index);
	return true;
}

//-----------------------------------------------------------------------------

bool ExportSceneDvDirModel::hasChildren(const QModelIndex &parent) const
{
	DvDirModelNode *node = getNode(parent);
	return node->hasChildren();
}

//-----------------------------------------------------------------------------

void ExportSceneDvDirModel::refresh(const QModelIndex &index)
{
	DvDirModelNode *node;
	if (!index.isValid())
		node = m_root;
	else
		node = getNode(index);
	if (!node)
		return;
	emit layoutAboutToBeChanged();
	emit beginRemoveRows(index, 0, node->getChildCount());
	node->refreshChildren();
	emit endRemoveRows();
	emit layoutChanged();
}

//=============================================================================
// ExportSceneTreeViewDelegate

ExportSceneTreeViewDelegate::ExportSceneTreeViewDelegate(ExportSceneTreeView *parent)
	: QItemDelegate(parent), m_treeView(parent)
{
}

//-----------------------------------------------------------------------------

ExportSceneTreeViewDelegate::~ExportSceneTreeViewDelegate()
{
}

//-----------------------------------------------------------------------------

void ExportSceneTreeViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
	QRect rect = option.rect;
	DvDirModelNode *node = DvDirModel::instance()->getNode(index);
	if (!node)
		return;

	DvDirModelProjectNode *pnode = dynamic_cast<DvDirModelProjectNode *>(node);
	DvDirModelFileFolderNode *fnode = dynamic_cast<DvDirModelFileFolderNode *>(node);

	if (node == m_treeView->getCurrentNode())
		painter->fillRect(rect, option.palette.highlight());

	QPixmap px = node->getPixmap(m_treeView->isExpanded(index));
	if (!px.isNull()) {
		int x = rect.left();
		int y = rect.top() + (rect.height() - px.height()) / 2;
		painter->drawPixmap(QPoint(x, y), px);
	}
	rect.adjust(pnode ? 26 : 20, 0, 0, 0);
	QVariant d = index.data();
	QString name = QString::fromStdWString(node->getName());
	if (node == m_treeView->getCurrentNode() && option.state & QStyle::State_Active)
		painter->setPen(Qt::white);
	else if (fnode && fnode->isProjectFolder())
		painter->setPen(Qt::blue);
	else
		painter->setPen(Qt::black);
	QRect nameBox;
	painter->drawText(rect, Qt::AlignVCenter | Qt::AlignLeft, name, &nameBox);

	if (pnode) {
		painter->setPen(Qt::black);
		if (pnode->isCurrent())
			painter->setBrush(Qt::red);
		else
			painter->setBrush(Qt::NoBrush);
		int d = 4;
		int y = (rect.height() - d) / 2;
		painter->drawEllipse(rect.x() - d - 4, rect.y() + y, d, d);
	}
	painter->setPen(Qt::magenta);
	painter->setBrush(Qt::NoBrush);
}

//-----------------------------------------------------------------------------

QSize ExportSceneTreeViewDelegate::sizeHint(const QStyleOptionViewItem &option,
											const QModelIndex &index) const
{
	return QSize(QItemDelegate::sizeHint(option, index).width() + 10, 22);
}

//=============================================================================
// ExportSceneTreeView

ExportSceneTreeView::ExportSceneTreeView(QWidget *parent)
	: QTreeView(parent)
{
	setStyleSheet("border:1px solid rgb(120,120,120);");
	m_model = new ExportSceneDvDirModel();
	setModel(m_model);
	header()->close();
	setItemDelegate(new ExportSceneTreeViewDelegate(this));
	setSelectionMode(QAbstractItemView::SingleSelection);

	//Connect all possible changes that can alter the
	//bottom horizontal scrollbar to resize contents...
	bool ret = connect(this, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeToConts()));
	ret = ret && connect(this, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(resizeToConts()));
	ret = ret && connect(this->model(), SIGNAL(layoutChanged()), this, SLOT(resizeToConts()));

	assert(ret);
	setAcceptDrops(true);
}

//-----------------------------------------------------------------------------

void ExportSceneTreeView::resizeToConts()
{
	resizeColumnToContents(0);
}

//-----------------------------------------------------------------------------

void ExportSceneTreeView::refresh()
{
	m_model->refresh(QModelIndex());
}

//-----------------------------------------------------------------------------

DvDirModelNode *ExportSceneTreeView::getCurrentNode() const
{
	QModelIndex index = currentIndex();
	DvDirModelNode *node = m_model->getNode(index);
	return node;
}

//-----------------------------------------------------------------------------

QSize ExportSceneTreeView::sizeHint() const
{
	return QSize(100, 100);
}

//-----------------------------------------------------------------------------

void ExportSceneTreeView::showEvent(QShowEvent *)
{
	refresh();
}

//-----------------------------------------------------------------------------

void ExportSceneTreeView::focusInEvent(QFocusEvent *event)
{
	QTreeView::focusInEvent(event);
	emit focusIn();
}

//=============================================================================
// ExportScenePopup

ExportScenePopup::ExportScenePopup(std::vector<TFilePath> scenes)
	: Dialog(TApp::instance()->getMainWindow(), true, false, "ExportScene"), m_scenes(scenes), m_createNewProject(false)
{
	setWindowTitle(tr("Export Scene"));

	bool ret = true;

	QVBoxLayout *layout = new QVBoxLayout(this);

	//  m_command = new QLabel(this);
	//  layout->addWidget(m_command);

	QButtonGroup *group = new QButtonGroup(this);
	group->setExclusive(true);

	//Choose Project
	QWidget *chooseProjectWidget = new QWidget(this);
	QVBoxLayout *chooseProjectLayout = new QVBoxLayout(chooseProjectWidget);

	m_chooseProjectButton = new QRadioButton(tr("Choose Existing Project"), chooseProjectWidget);
	group->addButton(m_chooseProjectButton, 0);
	m_chooseProjectButton->setChecked(true);
	chooseProjectLayout->addWidget(m_chooseProjectButton);

	m_projectTreeView = new ExportSceneTreeView(chooseProjectWidget);
	m_projectTreeView->setMinimumWidth(200);
	ret = ret && connect(m_projectTreeView, SIGNAL(focusIn()), this, SLOT(onProjectTreeViweFocusIn()));
	chooseProjectLayout->addWidget(m_projectTreeView);

	chooseProjectWidget->setLayout(chooseProjectLayout);
	layout->addWidget(chooseProjectWidget, 5);

	//New Project
	QWidget *newProjectWidget = new QWidget(this);
	QGridLayout *newProjectLayout = new QGridLayout(newProjectWidget);

	m_newProjectButton = new QRadioButton(tr("Create New Project"), newProjectWidget);
	group->addButton(m_newProjectButton, 1);
	newProjectLayout->addWidget(m_newProjectButton, 0, 0, 1, 2, Qt::AlignLeft);

	m_newProjectNameLabel = new QLabel(tr("Name:"), newProjectWidget);
	newProjectLayout->addWidget(m_newProjectNameLabel, 1, 0, 1, 1, Qt::AlignRight);

	m_newProjectName = new LineEdit(newProjectWidget);
	ret = ret && connect(m_newProjectName, SIGNAL(focusIn()), this, SLOT(onProjectNameFocusIn()));
	newProjectLayout->setColumnStretch(1, 5);
	newProjectLayout->addWidget(m_newProjectName, 1, 1, 1, 1, Qt::AlignLeft);

	newProjectWidget->setLayout(chooseProjectLayout);
	layout->addWidget(newProjectWidget);

	ret = ret && connect(group, SIGNAL(buttonClicked(int)), this, SLOT(switchMode(int)));

	addLayout(layout, false);

	QPushButton *okBtn = new QPushButton(tr("Export"), this);
	okBtn->setDefault(true);
	QPushButton *cancelBtn = new QPushButton(tr("Cancel"), this);
	connect(okBtn, SIGNAL(clicked()), this, SLOT(onExport()));
	connect(cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));

	addButtonBarWidget(okBtn, cancelBtn);

	switchMode(0);
	//  updateCommandLabel();

	assert(ret);
}

//-----------------------------------------------------------------------------

void ExportScenePopup::switchMode(int id)
{
	if (id == 0) //choose Existing Project
	{
		m_createNewProject = false;
		//m_projectTreeView->setEnabled(true);
	} else //create new project
	{
		assert(id == 1);
		m_createNewProject = true;
		//m_projectTreeView->setEnabled(false);
	}
}

//-----------------------------------------------------------------------------

void ExportScenePopup::onProjectTreeViweFocusIn()
{
	m_chooseProjectButton->setChecked(true);
	switchMode(0);
}

//-----------------------------------------------------------------------------

void ExportScenePopup::onProjectNameFocusIn()
{
	m_newProjectButton->setChecked(true);
	switchMode(1);
}

//-----------------------------------------------------------------------------

void ExportScenePopup::onExport()
{
	QApplication::setOverrideCursor(Qt::WaitCursor);
	TProjectManager *pm = TProjectManager::instance();
	TFilePath oldProjectPath = pm->getCurrentProjectPath();
	TFilePath projectPath;
	if (!m_createNewProject) {
		DvDirModelFileFolderNode *node = (DvDirModelFileFolderNode *)m_projectTreeView->getCurrentNode();
		if (!node || !pm->isProject(node->getPath())) {
			QApplication::restoreOverrideCursor();
			DVGui::warning(tr("The folder you selected is not a project."));
			return;
		}
		projectPath = pm->projectFolderToProjectPath(node->getPath());
		assert(projectPath != TFilePath());
	} else //Create project
	{
		projectPath = createNewProject();
		if (projectPath == TFilePath()) {
			QApplication::restoreOverrideCursor();
			return;
		}
	}
	pm->setCurrentProjectPath(projectPath);

	std::vector<TFilePath> newScenes;
	int i;
	for (i = 0; i < m_scenes.size(); i++) {
		TFilePath newScenePath = importScene(m_scenes[i]);
		if (newScenePath == TFilePath())
			continue;
		newScenes.push_back(newScenePath);
	}
	pm->setCurrentProjectPath(oldProjectPath);
	if (newScenes.empty()) {
		QApplication::restoreOverrideCursor();
		DVGui::warning(tr("There was an error exporting the scene."));
		return;
	}
	for (i = 0; i < newScenes.size(); i++)
		collectAssets(newScenes[i]);

	QApplication::restoreOverrideCursor();
	accept();
}

//-----------------------------------------------------------------------------

TFilePath ExportScenePopup::createNewProject()
{
	TProjectManager *pm = TProjectManager::instance();
	TFilePath projectName(m_newProjectName->text().toStdWString());
	if (projectName == TFilePath()) {
		DVGui::warning(tr("The project name cannot be empty or contain any of the following characters:(new line)   \\ / : * ? \"  |"));
		return TFilePath();
	}
	if (projectName.isAbsolute()) {
		// bad project name
		DVGui::warning(tr("The project name cannot be empty or contain any of the following characters:(new line)   \\ / : * ? \"  |"));
		return TFilePath();
	}
	if (pm->getProjectPathByName(projectName) != TFilePath()) {
		// project already exists
		DVGui::warning(tr("The project name you specified is already used."));
		return TFilePath();
	}

	TFilePath currentProjectRoot;
	DvDirModelFileFolderNode *node = dynamic_cast<DvDirModelFileFolderNode *>(m_projectTreeView->getCurrentNode());
	if (node)
		currentProjectRoot = node->getPath();
	else
		currentProjectRoot = pm->getCurrentProjectRoot();
	TFilePath projectFolder = currentProjectRoot + projectName;
	TFilePath projectPath = pm->projectFolderToProjectPath(projectFolder);
	TProject *project = new TProject();

	TProjectP currentProject = pm->getCurrentProject();
	assert(currentProject);
	int i;
	for (i = 0; i < (int)currentProject->getFolderCount(); i++)
		project->setFolder(currentProject->getFolderName(i), currentProject->getFolder(i));
	project->save(projectPath);
	DvDirModel::instance()->refreshFolder(currentProjectRoot);

	return projectPath;
}

//-----------------------------------------------------------------------------
/*
void ExportScenePopup::updateCommandLabel()
{
  if(m_scenes.empty())
    return;
  int sceneCount= m_scenes.size();
  if(sceneCount==1)
    m_command->setText(tr("Stai esportando la scena selezionata nel seguente progetto:"));
  else
    m_command->setText(tr("Stai esportando ") + QString::number(sceneCount) + tr(" scene nel seguente progetto:"));
}
*/