Blob Blame Raw


#include "fileselection.h"

// Tnz6 includes
#include "convertpopup.h"
#include "filebrowser.h"
#include "filedata.h"
#include "iocommand.h"
#include "menubarcommandids.h"
#include "flipbook.h"
#include "filebrowsermodel.h"
#include "exportscenepopup.h"
#include "tapp.h"

#ifndef LINETEST
#include "batches.h"
#endif

// TnzQt includes
#include "toonzqt/imageutils.h"
#include "toonzqt/dvdialog.h"
#include "toonzqt/infoviewer.h"
#include "toonzqt/icongenerator.h"
#include "toonzqt/gutil.h"
#include "historytypes.h"

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

// TnzCore includes
#include "tfiletype.h"
#include "tsystem.h"

// Qt includes
#include <QApplication>
#include <QClipboard>
#include <QDesktopServices>
#include <QUrl>
#include <QVariant>
#include <QMainWindow>

using namespace DVGui;

//TODO: spostare i comandi in FileBrowser?

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

namespace
{

//=============================================================================
//  CopyFilesUndo
//-----------------------------------------------------------------------------

class CopyFilesUndo : public TUndo
{
	QMimeData *m_oldData;
	QMimeData *m_newData;

public:
	CopyFilesUndo(QMimeData *oldData,
				  QMimeData *newData)
		: m_oldData(oldData), m_newData(newData)
	{
	}

	void undo() const
	{
		QClipboard *clipboard = QApplication::clipboard();
		clipboard->setMimeData(cloneData(m_oldData), QClipboard::Clipboard);
	}

	void redo() const
	{
		QClipboard *clipboard = QApplication::clipboard();
		clipboard->setMimeData(cloneData(m_newData), QClipboard::Clipboard);
	}

	int getSize() const
	{
		return sizeof(*this);
	}

	QString getHistoryString()
	{
		return QObject::tr("Copy File");
	}
};

//=============================================================================
//  PasteFilesUndo
//-----------------------------------------------------------------------------

class PasteFilesUndo : public TUndo
{
	std::vector<TFilePath> m_newFiles;
	TFilePath m_folder;

public:
	PasteFilesUndo(std::vector<TFilePath> files, TFilePath folder)
		: m_newFiles(files), m_folder(folder)
	{
	}

	~PasteFilesUndo()
	{
	}

	void undo() const
	{
		int i;
		for (i = 0; i < (int)m_newFiles.size(); i++) {
			TFilePath path = m_newFiles[i];
			if (!TSystem::doesExistFileOrLevel(path))
				continue;
			try {
				TSystem::removeFileOrLevel(path);
			} catch (...) {
			}
		}
		FileBrowser::refreshFolder(m_folder);
	}

	void redo() const
	{
		if (!TSystem::touchParentDir(m_folder))
			TSystem::mkDir(m_folder);
		const FileData *data = dynamic_cast<const FileData *>(QApplication::clipboard()->mimeData());
		if (!data)
			return;
		TApp *app = TApp::instance();
		std::vector<TFilePath> files;
		data->getFiles(m_folder, files);
		FileBrowser::refreshFolder(m_folder);
	}

	int getSize() const
	{
		return sizeof(*this);
	}

	QString getHistoryString()
	{
		QString str = QObject::tr("Paste  File  : ");
		for (int i = 0; i < (int)m_newFiles.size(); i++) {
			if (i != 0)
				str += QString(", ");
			str += QString::fromStdString(m_newFiles[i].getLevelName());
		}
		return str;
	}
};

//=============================================================================
//  DuplicateUndo
//-----------------------------------------------------------------------------

class DuplicateUndo : public TUndo
{
	std::vector<TFilePath> m_newFiles;
	std::vector<TFilePath> m_files;

public:
	DuplicateUndo(std::vector<TFilePath> files, std::vector<TFilePath> newFiles)
		: m_files(files), m_newFiles(newFiles)
	{
	}

	~DuplicateUndo()
	{
	}

	void undo() const
	{
		int i;
		for (i = 0; i < (int)m_newFiles.size(); i++) {
			TFilePath path = m_newFiles[i];
			if (!TSystem::doesExistFileOrLevel(path))
				continue;
			if (path.getType() == "tnz")
				TSystem::rmDirTree(path.getParentDir() + (path.getName() + "_files"));
			try {
				TSystem::removeFileOrLevel(path);
			} catch (...) {
			}
		}
		FileBrowser::refreshFolder(m_newFiles[0].getParentDir());
	}

	void redo() const
	{
		int i;
		for (i = 0; i < (int)m_files.size(); i++) {
			TFilePath fp = m_files[i];
			ImageUtils::duplicate(fp);
			FileBrowser::refreshFolder(fp.getParentDir());
		}
		FileBrowser::refreshFolder(m_files[0].getParentDir());
	}

	int getSize() const
	{
		return sizeof(*this);
	}

	QString getHistoryString()
	{
		QString str = QObject::tr("Duplicate  File  : ");
		int i;
		for (i = 0; i < (int)m_files.size(); i++) {
			if (i != 0)
				str += QString(",  ");

			TFilePath fp = m_files[i];
			TFilePath newFp = m_newFiles[i];

			str += QString("%1 > %2")
					   .arg(QString::fromStdString(fp.getLevelName()))
					   .arg(QString::fromStdString(newFp.getLevelName()));
		}
		return str;
	}
};

//-----------------------------------------------------------------------------
}

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

FileSelection::FileSelection()
	: m_exportScenePopup(0)
{
}

FileSelection::~FileSelection()
{
	m_infoViewers.clear();
}

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

void FileSelection::getSelectedFiles(std::vector<TFilePath> &files)
{
	if (!getModel())
		return;
	const std::set<int> &indices = getSelectedIndices();
	std::set<int>::const_iterator it;
	for (it = indices.begin(); it != indices.end(); ++it) {
		QString name = getModel()->getItemData(*it, DvItemListModel::FullPath).toString();
		TFilePath fp(name.toStdWString());
		files.push_back(fp);
	}
}

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

void FileSelection::enableCommands()
{
	DvItemSelection::enableCommands();
	enableCommand(this, MI_DuplicateFile, &FileSelection::duplicateFiles);
	enableCommand(this, MI_Clear, &FileSelection::deleteFiles);
	enableCommand(this, MI_Copy, &FileSelection::copyFiles);
	enableCommand(this, MI_Paste, &FileSelection::pasteFiles);
	enableCommand(this, MI_ShowFolderContents, &FileSelection::showFolderContents);
	enableCommand(this, MI_ConvertFiles, &FileSelection::convertFiles);
	enableCommand(this, MI_AddToBatchRenderList, &FileSelection::addToBatchRenderList);
	enableCommand(this, MI_AddToBatchCleanupList, &FileSelection::addToBatchCleanupList);
	enableCommand(this, MI_CollectAssets, &FileSelection::collectAssets);
	enableCommand(this, MI_ImportScenes, &FileSelection::importScenes);
	enableCommand(this, MI_ExportScenes, &FileSelection::exportScenes);
	enableCommand(this, MI_SelectAll, &FileSelection::selectAll);
}

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

void FileSelection::addToBatchRenderList()
{
#ifndef LINETEST
#ifdef BRAVODEMO
	DVGui::featureNotAvelaible();
#else
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	int i;
	for (i = 0; i < files.size(); i++)
		BatchesController::instance()->addComposerTask(files[i]);

	MsgBox(INFORMATION, QObject::tr(" Task added to the Batch Render List."));
#endif
#endif
}

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

void FileSelection::addToBatchCleanupList()
{
#ifndef LINETEST
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	int i;
	for (i = 0; i < files.size(); i++)
		BatchesController::instance()->addCleanupTask(files[i]);

	MsgBox(INFORMATION, QObject::tr(" Task added to the Batch Cleanup List."));
#endif
}

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

void FileSelection::deleteFiles()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	if (files.empty())
		return;

	QString question;
	if (files.size() == 1) {
		QString fn = QString::fromStdWString(files[0].getWideString());
		question = QObject::tr("Deleting %1. Are you sure?").arg(fn);
	} else {
		question = QObject::tr("Deleting %n files. Are you sure?", "", (int)files.size());
	}
	int ret = MsgBox(question, QObject::tr("Delete"), QObject::tr("Cancel"), 1);
	if (ret == 2 || ret == 0)
		return;

	int i;
	for (i = 0; i < (int)files.size(); i++) {
		TSystem::moveFileOrLevelToRecycleBin(files[i]);
		IconGenerator::instance()->remove(files[i]);
		// TODO: cancellare anche xxxx_files se files[i] == xxxx.tnz
	}
	selectNone();
	FileBrowser::refreshFolder(files[0].getParentDir());
}

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

void FileSelection::copyFiles()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	if (files.empty())
		return;

	QClipboard *clipboard = QApplication::clipboard();
	QMimeData *oldData = cloneData(clipboard->mimeData());
	FileData *data = new FileData();
	data->setFiles(files);
	QApplication::clipboard()->setMimeData(data);
	QMimeData *newData = cloneData(clipboard->mimeData());

	TUndoManager::manager()->add(new CopyFilesUndo(oldData, newData));
}

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

void FileSelection::pasteFiles()
{
	const FileData *data = dynamic_cast<const FileData *>(QApplication::clipboard()->mimeData());
	if (!data)
		return;
	TApp *app = TApp::instance();
	FileBrowser *model = dynamic_cast<FileBrowser *>(getModel());
	if (!model)
		return;
	TFilePath folder = model->getFolder();
	std::vector<TFilePath> newFiles;
	data->getFiles(folder, newFiles);
	FileBrowser::refreshFolder(folder);
	TUndoManager::manager()->add(new PasteFilesUndo(newFiles, folder));
}

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

void FileSelection::showFolderContents()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	TFilePath folderPath;
	if (!files.empty())
		folderPath = files[0].getParentDir();
	if (folderPath.isEmpty()) {
		FileBrowser *model = dynamic_cast<FileBrowser *>(getModel());
		if (!model)
			return;
		folderPath = model->getFolder();
	}
	if (TSystem::isUNC(folderPath))
		QDesktopServices::openUrl(QUrl(QString::fromStdWString(folderPath.getWideString())));
	else
		QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdWString(folderPath.getWideString())));
}

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

extern QWidget *CurrentOpenedBrowser;

void FileSelection::viewFileInfo()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	if (files.empty())
		return;
	int j = 0;
	for (j = 0; j < files.size(); j++) {
		InfoViewer *infoViewer = 0;
		int i;
		for (i = 0; i < m_infoViewers.size(); i++) {
			InfoViewer *v = m_infoViewers.at(i);
			if (!v->isHidden())
				continue;
			infoViewer = v;
			break;
		}
		if (!infoViewer) {
			infoViewer = new InfoViewer(CurrentOpenedBrowser);
			m_infoViewers.append(infoViewer);
		}
		infoViewer->setItem(0, 0, files[j]);
	}
}

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

void FileSelection::viewFile()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	int i = 0;
	for (i = 0; i < files.size(); i++) {
		if (!TFileType::isViewable(TFileType::getInfo(files[0])))
			continue;

		if (Preferences::instance()->isDefaultViewerEnabled() &&
			(files[i].getType() == "mov" || files[i].getType() == "avi" || files[i].getType() == "3gp"))
			QDesktopServices::openUrl(QUrl("file:///" + toQString(files[i])));
		else
			::viewFile(files[i]);
	}
}

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

void FileSelection::convertFiles()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	if (files.empty())
		return;

	static ConvertPopup *popup = new ConvertPopup(false);
	if (popup->isConverting()) {
		DVGui::MsgBox(INFORMATION, QObject::tr("A convertion task is in progress! wait until it stops or cancel it"));
		return;
	}
	popup->setFiles(files);
	popup->exec();
}

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

void FileSelection::premultiplyFiles()
{
	QString question = QObject::tr("You are going to premultiply selected files.\nThe operation cannot be undone: are you sure?");
	int ret = MsgBox(question, QObject::tr("Premultiply"), QObject::tr("Cancel"), 1);
	if (ret == 2 || ret == 0)
		return;

	std::vector<TFilePath> files;
	getSelectedFiles(files);
	int i;
	for (i = 0; i < (int)files.size(); i++) {
		TFilePath fp = files[i];
		ImageUtils::premultiply(fp);
	}
}

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

void FileSelection::duplicateFiles()
{
	std::vector<TFilePath> files;
	std::vector<TFilePath> newFiles;
	getSelectedFiles(files);
	int i;
	for (i = 0; i < (int)files.size(); i++) {
		TFilePath fp = files[i];
		TFilePath newPath = ImageUtils::duplicate(fp);
		newFiles.push_back(newPath);
		FileBrowser::refreshFolder(fp.getParentDir());
	}
	TUndoManager::manager()->add(new DuplicateUndo(files, newFiles));
}

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

int collectAssets(TFilePath scenePath)
{
	// bool dirtyFlag = TNotifier::instance()->getDirtyFlag();
	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);
	}
	// TNotifier::instance()->setDirtyFlag(dirtyFlag);
	return count;
}

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

void FileSelection::collectAssets()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	if (files.empty())
		return;
	int collectedAssets = 0;

	int count = files.size();

	if (count > 1) {
		QMainWindow *mw = TApp::instance()->getMainWindow();
		ProgressDialog progress(tr("Collecting assets..."), tr("Abort"), 0, count, mw);
		progress.setWindowModality(Qt::WindowModal);

		int i;
		for (i = 1; i <= count; i++) {
			collectedAssets += ::collectAssets(files[i - 1]);
			progress.setValue(i);
			if (progress.wasCanceled())
				break;
		}
		progress.setValue(count);
	} else {
		collectedAssets = ::collectAssets(files[0]);
	}
	if (collectedAssets == 0)
		DVGui::MsgBox(INFORMATION, QObject::tr("There are no assets to collect"));
	else if (collectedAssets == 1)
		DVGui::MsgBox(INFORMATION, QObject::tr("One asset imported"));
	else
		DVGui::MsgBox(INFORMATION, QObject::tr("%1 assets imported").arg(collectedAssets));
	DvDirModel::instance()->refreshFolder(TProjectManager::instance()->getCurrentProjectPath().getParentDir());
}

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

int importScene(TFilePath scenePath)
{
	// bool dirtyFlag = TNotifier::instance()->getDirtyFlag();
	ToonzScene scene;
	try {
		IoCmd::loadScene(scene, scenePath, true);
	} catch (TException &e) {
		MsgBox(CRITICAL, QObject::tr("Error loading scene %1 :%2").arg(toQString(scenePath)).arg(QString::fromStdWString(e.getMessage())));
		return 0;
	} catch (...) {
		// TNotifier::instance()->notify(TGlobalChange(true));
		MsgBox(CRITICAL, QObject::tr("Error loading scene %1").arg(toQString(scenePath)));
		return 0;
	}

	try {
		scene.save(scene.getScenePath());
	} catch (TException &e) {
		MsgBox(CRITICAL, QObject::tr("There was an error saving the %1 scene.").arg(toQString(scenePath)));
		return 0;
	}

	DvDirModel::instance()->refreshFolder(TProjectManager::instance()->getCurrentProjectPath().getParentDir());

	// TNotifier::instance()->setDirtyFlag(dirtyFlag);
	return 1;
}

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

void FileSelection::importScenes()
{
#ifdef BRAVODEMO
	DVGui::featureNotAvelaible();

#else
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	if (files.empty())
		return;
	int importedSceneCount = 0;

	int count = files.size();

	if (count > 1) {
		QMainWindow *mw = TApp::instance()->getMainWindow();
		ProgressDialog progress(tr("Importing scenes..."), tr("Abort"), 0, count, mw);
		progress.setWindowModality(Qt::WindowModal);

		int i;
		for (i = 1; i <= count; i++) {
			int ret = ::importScene(files[i - 1]);
			importedSceneCount += ret;
			progress.setValue(i);
			if (progress.wasCanceled())
				break;
		}
		progress.setValue(count);
	} else {
		int ret = ::importScene(files[0]);
		importedSceneCount += ret;
	}
	if (importedSceneCount == 0)
		DVGui::MsgBox(INFORMATION, QObject::tr("No scene imported"));
	else if (importedSceneCount == 1)
		DVGui::MsgBox(INFORMATION, QObject::tr("One scene imported"));
	else
		DVGui::MsgBox(INFORMATION, QString::number(importedSceneCount) + QObject::tr("%1 scenes imported").arg(importedSceneCount));
#endif
}
//------------------------------------------------------------------------

void FileSelection::exportScenes()
{
	std::vector<TFilePath> files;
	getSelectedFiles(files);
	if (!m_exportScenePopup)
		m_exportScenePopup = new ExportScenePopup(files);
	else
		m_exportScenePopup->setScenes(files);
	m_exportScenePopup->show();
}

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

void FileSelection::selectAll()
{
	DvItemSelection::selectAll();
	const std::set<int> &indices = getSelectedIndices();
	if (indices.size()) {
		std::set<int>::const_iterator it;
		it = indices.begin();
		QString name = getModel()->getItemData(*it, DvItemListModel::FullPath).toString();
		TFilePath fp(name.toStdWString());
		FileBrowser::refreshFolder(fp.getParentDir());
	}
}