Blob Blame Raw
#include "svncommitdialog.h"
// Tnz6 includes
#include "tapp.h"
// TnzQt includes
#include "toonzqt/gutil.h"
// TnzLib includes
#include "toonz/toonzscene.h"
#include "toonz/txshlevel.h"
#include "toonz/txshsimplelevel.h"
// TnzCore includes
#include "tfilepath.h"
#include "tsystem.h"
// Qt includes
#include <QWidget>
#include <QLabel>
#include <QMovie>
#include <QFile>
#include <QBoxLayout>
#include <QFormLayout>
#include <QPushButton>
#include <QCheckBox>
#include <QTreeWidget>
#include <QPlainTextEdit>
#include <QHeaderView>
#include <QHostInfo>
#include <QTextStream>
#include <QMainWindow>
//=============================================================================
// SVNCommitDialog
//-----------------------------------------------------------------------------
SVNCommitDialog::SVNCommitDialog(QWidget *parent, const QString &workingDir,
const QStringList &files, bool folderOnly,
int sceneIconAdded)
: Dialog(TApp::instance()->getMainWindow(), true, false)
, m_commitSceneContentsCheckBox(0)
, m_workingDir(workingDir)
, m_files(files)
, m_folderOnly(folderOnly)
, m_targetTempFile(0)
, m_selectionCheckBox(0)
, m_selectionLabel(0)
, m_sceneIconAdded(sceneIconAdded)
, m_folderAdded(0) {
setModal(false);
setAttribute(Qt::WA_DeleteOnClose, true);
setWindowTitle(tr("Version Control: Put changes"));
if (m_folderOnly)
setMinimumSize(320, 320);
else
setMinimumSize(300, 180);
QWidget *container = new QWidget;
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->setAlignment(Qt::AlignHCenter);
mainLayout->setMargin(0);
m_treeWidget = new QTreeWidget;
m_treeWidget->header()->hide();
m_treeWidget->hide();
if (m_folderOnly) {
m_treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_treeWidget->setIconSize(QSize(21, 17));
}
m_treeWidget->setStyleSheet("QTreeWidget { border: 1px solid gray; }");
if (m_folderOnly) {
mainLayout->addWidget(m_treeWidget);
QHBoxLayout *belowTreeLayout = new QHBoxLayout;
belowTreeLayout->setMargin(0);
m_selectionCheckBox = new QCheckBox(tr("Select / Deselect All"), 0);
connect(m_selectionCheckBox, SIGNAL(clicked(bool)), this,
SLOT(onSelectionCheckBoxClicked(bool)));
m_selectionLabel = new QLabel;
m_selectionLabel->setText(tr("0 Selected / 0 Total"));
m_selectionCheckBox->hide();
m_selectionLabel->hide();
belowTreeLayout->addWidget(m_selectionCheckBox);
belowTreeLayout->addStretch();
belowTreeLayout->addWidget(m_selectionLabel);
mainLayout->addLayout(belowTreeLayout);
}
QHBoxLayout *hLayout = new QHBoxLayout;
m_waitingLabel = new QLabel;
QMovie *waitingMove = new QMovie(":Resources/waiting.gif");
waitingMove->setParent(this);
m_waitingLabel->setMovie(waitingMove);
waitingMove->setCacheMode(QMovie::CacheAll);
waitingMove->start();
m_textLabel = new QLabel;
m_textLabel->setText(tr("Getting repository status..."));
hLayout->addStretch();
hLayout->addWidget(m_waitingLabel);
hLayout->addWidget(m_textLabel);
hLayout->addStretch();
mainLayout->addLayout(hLayout);
if (!m_folderOnly)
mainLayout->addWidget(m_treeWidget);
else
mainLayout->addSpacing(10);
QFormLayout *formLayout = new QFormLayout;
formLayout->setLabelAlignment(Qt::AlignRight);
formLayout->setFormAlignment(Qt::AlignHCenter | Qt::AlignTop);
formLayout->setSpacing(10);
formLayout->setMargin(0);
m_commentTextEdit = new QPlainTextEdit;
m_commentTextEdit->setMaximumHeight(50);
m_commentTextEdit->hide();
m_commentLabel = new QLabel(tr("Comment:"));
m_commentLabel->setFixedWidth(55);
m_commentLabel->hide();
formLayout->addRow(m_commentLabel, m_commentTextEdit);
if (!m_folderOnly) {
m_commitSceneContentsCheckBox = new QCheckBox(this);
connect(m_commitSceneContentsCheckBox, SIGNAL(toggled(bool)), this,
SLOT(onCommiSceneContentsToggled(bool)));
m_commitSceneContentsCheckBox->setChecked(false);
m_commitSceneContentsCheckBox->hide();
m_commitSceneContentsCheckBox->setText(tr("Put Scene Contents"));
formLayout->addRow("", m_commitSceneContentsCheckBox);
}
mainLayout->addLayout(formLayout);
container->setLayout(mainLayout);
beginHLayout();
addWidget(container, false);
endHLayout();
m_commitButton = new QPushButton(tr("Put"));
m_commitButton->setEnabled(false);
connect(m_commitButton, SIGNAL(clicked()), this,
SLOT(onCommitButtonClicked()));
m_cancelButton = new QPushButton(tr("Cancel"));
connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
addButtonBarWidget(m_commitButton, m_cancelButton);
// 0. Connect for svn errors (that may occurs everythings)
connect(&m_thread, SIGNAL(error(const QString &)), this,
SLOT(onError(const QString &)));
// 1. Getting status (with show-updates enabled...)
connect(&m_thread, SIGNAL(statusRetrieved(const QString &)), this,
SLOT(onStatusRetrieved(const QString &)));
m_thread.getSVNStatus(m_workingDir, m_files, true);
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onCommitButtonClicked() {
if (m_folderOnly) {
QMapIterator<QString, QTreeWidgetItem *> i(m_items);
while (i.hasNext()) {
i.next();
QTreeWidgetItem *item = i.value();
if (item && item->checkState(0) == Qt::Checked) {
if (item->data(0, Qt::UserRole + 1).toBool())
m_filesToAdd.append(item->data(0, Qt::UserRole).toString());
else
m_filesToCommit.append(item->data(0, Qt::UserRole).toString());
}
}
} else
m_commitSceneContentsCheckBox->hide();
m_commitButton->setEnabled(false);
// Check the status of the scene resource in order to see if some items has
// to be added or can be directly committed
if (!m_folderOnly && !m_sceneResourcesToCommit.empty()) {
m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
connect(&m_thread, SIGNAL(statusRetrieved(const QString &)), this,
SLOT(onResourcesStatusRetrieved(const QString &)));
m_thread.getSVNStatus(m_workingDir, m_sceneResourcesToCommit, true);
return;
}
// addFiles > getStatus > setProperties > commitFiles
addFiles();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::addFiles() {
m_waitingLabel->show();
m_commentLabel->hide();
m_commentTextEdit->hide();
m_treeWidget->hide();
if (m_folderOnly) {
m_selectionCheckBox->hide();
m_selectionLabel->hide();
}
m_textLabel->show();
int fileToAddCount = m_filesToAdd.size();
if (fileToAddCount + m_sceneResourcesToCommit.size() > 0) {
m_textLabel->setText(
tr("Adding %1 items...")
.arg(QString::number(fileToAddCount - m_sceneIconAdded)));
QStringList args;
args << "add";
args << "--parents";
args << "-N"; // Non recursive add
// Use a temporary file to store all the files list
m_targetTempFile = new QFile(m_workingDir + "/" + "tempAddFile");
if (m_targetTempFile->open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(m_targetTempFile);
for (int i = 0; i < fileToAddCount; i++) {
QString path = m_filesToAdd.at(i);
out << path + "\n";
m_filesToCommit.push_back(path);
}
for (int i = 0; i < m_sceneResourcesToCommit.size(); i++)
out << m_sceneResourcesToCommit.at(i) + "\n";
}
m_targetTempFile->close();
args << "--targets";
args << "tempAddFile";
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), SLOT(onAddDone()));
m_thread.executeCommand(m_workingDir, "svn", args);
} else
onAddDone();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::commitFiles() {
m_waitingLabel->show();
int fileToCommitCount = m_filesToCommit.size();
if (fileToCommitCount > 0) {
QStringList args;
args << "commit";
args << "-N"; // non recursive commit
// Use a temporary file to store all the files list
m_targetTempFile = new QFile(m_workingDir + "/" + "tempCommitFile");
if (m_targetTempFile->open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(m_targetTempFile);
for (int i = 0; i < fileToCommitCount; i++)
out << m_filesToCommit.at(i) + "\n";
int sceneResourcesCount = m_sceneResourcesToCommit.size();
for (int i = 0; i < sceneResourcesCount; i++)
out << m_sceneResourcesToCommit.at(i) + "\n";
}
m_targetTempFile->close();
args << "--targets";
args << "tempCommitFile";
if (!m_commentTextEdit->toPlainText().isEmpty())
args << QString("-m").append(m_commentTextEdit->toPlainText());
else
args << QString("-m").append(VersionControl::instance()->getUserName() +
" commit changes.");
m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), SLOT(onCommitDone()));
m_thread.executeCommand(m_workingDir, "svn", args);
} else
onCommitDone();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::setPropertyFiles() {
m_textLabel->setText(tr("Set needs-lock property..."));
int count = m_filesAdded.size();
if (count > 0) {
QStringList args;
args << "propset"
<< "svn:needs-lock"
<< "'*'";
// Use a temporary file to store all the files list
m_targetTempFile = new QFile(m_workingDir + "/" + "tempPropSetFile");
if (m_targetTempFile->open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(m_targetTempFile);
for (int i = 0; i < count; i++) out << m_filesAdded.at(i) + "\n";
}
m_targetTempFile->close();
args << "--targets";
args << "tempPropSetFile";
m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)),
SLOT(onSetPropertyDone()));
m_thread.executeCommand(m_workingDir, "svn", args);
} else
onSetPropertyDone();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::switchToCloseButton() {
m_waitingLabel->hide();
m_commitButton->disconnect();
m_commitButton->setText(tr("Close"));
m_commitButton->setEnabled(true);
m_cancelButton->hide();
connect(m_commitButton, SIGNAL(clicked()), this, SLOT(close()));
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onAddDone() {
if (m_targetTempFile) {
QFile::remove(m_targetTempFile->fileName());
delete m_targetTempFile;
m_targetTempFile = 0;
}
int fileToAddCount = m_filesToAdd.size();
if (fileToAddCount + m_sceneResourcesToCommit.size() > 0) {
m_textLabel->setText(tr("Getting repository status..."));
m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
connect(&m_thread, SIGNAL(statusRetrieved(const QString &)), this,
SLOT(onStatusRetrievedAfterAdd(const QString &)));
QStringList oldFilesAndResources;
oldFilesAndResources.append(m_files);
for (int i = 0; i < m_filesToAdd.size(); i++) {
QString fileToAdd = m_filesToAdd.at(i);
if (!oldFilesAndResources.contains(fileToAdd))
oldFilesAndResources.append(fileToAdd);
}
int resCount = m_sceneResourcesToCommit.size();
for (int r = 0; r < resCount; r++) {
QString path = m_sceneResourcesToCommit.at(r);
int lastIndex = path.lastIndexOf(QRegExp("\\\\|/"));
while (lastIndex != -1) {
path = path.left(lastIndex);
if (!oldFilesAndResources.contains(path) && path != "..")
oldFilesAndResources.append(path);
lastIndex = path.lastIndexOf(QRegExp("\\\\|/"));
}
}
// Add also sceneIcons folder
for (int x = 0; x < m_filesToAdd.size(); x++) {
QString s = m_filesToAdd.at(x);
if (s.contains("sceneIcons") && s.endsWith(".png")) {
int lastIndex = s.lastIndexOf(QRegExp("\\\\|/"));
while (lastIndex != -1) {
s = s.left(lastIndex);
if (!oldFilesAndResources.contains(s) && s != "..")
oldFilesAndResources.append(s);
lastIndex = s.lastIndexOf(QRegExp("\\\\|/"));
}
}
}
m_thread.getSVNStatus(m_workingDir, oldFilesAndResources, true);
} else {
int fileToCommitCount = m_filesToCommit.size();
if (fileToCommitCount > 0)
m_textLabel->setText(
tr("Committing %1 items...")
.arg(QString::number(fileToCommitCount - m_sceneIconAdded)));
// Then we commits changes (add, remove, modified files)
commitFiles();
}
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onCommitDone() {
m_waitingLabel->hide();
m_textLabel->setText(tr("Put done successfully."));
if (m_targetTempFile) {
QFile::remove(m_targetTempFile->fileName());
delete m_targetTempFile;
m_targetTempFile = 0;
}
QStringList files;
for (int i = 0; i < m_filesToCommit.size(); i++)
files.append(m_filesToCommit.at(i));
emit done(files);
switchToCloseButton();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onSetPropertyDone() {
if (m_targetTempFile) {
QFile::remove(m_targetTempFile->fileName());
delete m_targetTempFile;
m_targetTempFile = 0;
}
if (m_filesToCommit.size() + m_sceneResourcesToCommit.size() > 0) {
int putCount = m_filesToCommit.size() - m_sceneIconAdded - m_folderAdded;
for (int i = 0; i < m_sceneResourcesToCommit.size(); i++) {
if (m_filesToCommit.contains(m_sceneResourcesToCommit.at(i))) putCount--;
}
m_textLabel->setText(
tr("Putting %1 items...").arg(QString::number(putCount)));
}
// Then we commits changes (add, remove, modified files)
commitFiles();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onResourcesStatusRetrieved(const QString &xmlResponse) {
SVNStatusReader sr(xmlResponse);
m_status = sr.getStatus();
m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
checkFiles(true);
// addFiles > getStatus > setProperties > commitFiles
addFiles();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onStatusRetrieved(const QString &xmlResponse) {
SVNStatusReader sr(xmlResponse);
m_status = sr.getStatus();
m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
checkFiles(m_folderOnly);
if (!m_folderOnly) {
// Add, if necessary the scene icons: only when the folder "sceneIcons" is
// unversioned the status
// doesn't contains the scene icon information, so I added here manually...
if (m_sceneIconAdded != 0) {
for (int i = 0; i < m_files.size(); i++) {
QString s = m_files.at(i);
if (s.contains("sceneIcons") && s.endsWith(".png") &&
!m_filesToAdd.contains(s))
m_filesToAdd.append(s);
}
}
m_filesToPut.append(m_filesToAdd);
m_filesToPut.append(m_filesToCommit);
int filesToPutCount = m_filesToPut.size();
if (filesToPutCount == 0) {
m_textLabel->setText(tr("No items to put."));
switchToCloseButton();
} else {
m_textLabel->setText(
tr("%1 items to put.").arg(filesToPutCount - m_sceneIconAdded));
initTreeWidget();
for (int i = 0; i < filesToPutCount; i++) {
if (m_filesToPut.at(i).endsWith(".tnz")) {
m_commitSceneContentsCheckBox->show();
break;
}
}
m_waitingLabel->hide();
m_commentLabel->show();
m_commentTextEdit->show();
m_commitButton->setEnabled(true);
}
return;
}
if (m_items.size() == 0) {
m_textLabel->setText(tr("No items to put."));
switchToCloseButton();
} else {
if (m_folderOnly) {
updateTreeSelectionLabel();
connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this,
SLOT(onItemChanged(QTreeWidgetItem *)));
m_treeWidget->show();
m_selectionCheckBox->show();
m_selectionLabel->show();
}
m_waitingLabel->hide();
m_textLabel->hide();
m_commentLabel->show();
m_commentTextEdit->show();
if (!m_folderOnly) m_commitButton->setEnabled(true);
}
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onStatusRetrievedAfterAdd(const QString &xmlResponse) {
SVNStatusReader sr(xmlResponse);
QList<SVNStatus> status = sr.getStatus();
m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
int statusCount = status.size();
for (int i = 0; i < statusCount; i++) {
SVNStatus s = status.at(i);
if (s.m_item == "added") {
// Pay attention: the svn:needs-lock property (or any property) cannot be
// set on folders
// Remove folder from files to Add
QFileInfo fi(s.m_path);
if (fi.isAbsolute()) {
if (fi.isFile()) m_filesAdded.append(s.m_path);
} else {
fi = QFileInfo(m_workingDir + "/" + s.m_path);
if (fi.isFile()) {
if (!m_filesAdded.contains(s.m_path)) m_filesAdded.append(s.m_path);
} else {
if (!m_filesToCommit.contains(s.m_path)) {
m_filesToCommit.append(s.m_path);
m_folderAdded++;
}
}
}
}
}
setPropertyFiles();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::checkFiles(bool isExternalFiles) {
int statusCount = m_status.size();
for (int i = 0; i < statusCount; i++) {
SVNStatus s = m_status.at(i);
if (s.m_path == "." || s.m_path == "..") continue;
if (s.m_item == "unversioned") {
if (isExternalFiles || m_files.contains(s.m_path)) {
if (m_folderOnly)
addUnversionedItem(s.m_path);
else
m_filesToAdd.append(s.m_path);
}
} else if (s.m_item != "normal" && s.m_item != "incomplete" &&
s.m_item != "missing") {
if (isExternalFiles || m_files.contains(s.m_path)) {
if (m_folderOnly)
addModifiedItem(s.m_path);
else
m_filesToCommit.append(s.m_path);
}
}
}
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::addUnversionedItem(const QString &relativePath) {
// Split the string in order to recreate the hierarchy
QStringList list = relativePath.split(QRegExp("\\\\|/"));
QTreeWidgetItem *parent = 0;
QString tempString = "";
QIcon folderIcon = QIcon(":Resources/vcfolder_close.png");
int levelCount = list.count();
for (int i = 0; i < levelCount; i++) {
i == 0 ? tempString.append(list.at(i))
: tempString.append("/" + list.at(i));
if (m_items.contains(tempString))
parent = m_items.value(tempString);
else {
QFileInfo fi(m_workingDir + "/" + tempString);
// Don't add and show hidden files
if (fi.isHidden()) continue;
QTreeWidgetItem *item;
if (parent)
item = new QTreeWidgetItem(parent, QStringList(list.at(i)));
else
item = new QTreeWidgetItem(m_treeWidget, QStringList(list.at(i)));
if (fi.isDir()) item->setIcon(0, folderIcon);
if (relativePath == tempString) {
item->setCheckState(0, m_folderOnly ? Qt::Unchecked : Qt::Checked);
item->setData(0, Qt::UserRole, tempString);
item->setData(0, Qt::UserRole + 1, true);
}
m_treeWidget->addTopLevelItem(item);
m_items[tempString] = item;
parent = item;
}
}
// Add unversioned dir entries (recursively)
QFileInfo fi(m_workingDir + "/" + relativePath);
if (fi.isDir() && !fi.isHidden()) {
QDir dir(m_workingDir + "/" + relativePath);
addUnversionedFolders(dir, relativePath);
}
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::addUnversionedFolders(const QDir &dir,
const QString &relativePath) {
QStringList entries =
dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
int count = entries.count();
QIcon folderIcon = QIcon(":Resources/vcfolder_close.png");
for (int i = 0; i < count; i++) {
QString entry = entries.at(i);
QFileInfo fi(m_workingDir + "/" + relativePath + "/" + entry);
// Don't add hidden files and folders
if (fi.isHidden()) continue;
if (fi.isDir()) {
QTreeWidgetItem *parent = m_items[relativePath];
QTreeWidgetItem *item = new QTreeWidgetItem(parent, QStringList(entry));
item->setCheckState(0, m_folderOnly ? Qt::Unchecked : Qt::Checked);
item->setData(0, Qt::UserRole, relativePath + "/" + entry);
item->setData(0, Qt::UserRole + 1, true);
item->setIcon(0, folderIcon);
if (parent) parent->insertChild(0, item);
m_items[relativePath + "/" + entry] = item;
QDir dir2(m_workingDir + "/" + relativePath + "/" + entry);
addUnversionedFolders(dir2, relativePath + "/" + entry);
}
QStringList list = (entries.at(i)).split(QRegExp("\\\\|/"));
QTreeWidgetItem *parent = m_items[relativePath];
QString tempString = relativePath;
int levelCount = list.count();
for (int l = 0; l < levelCount; l++) {
tempString.append("/" + list.at(l));
if (m_items.contains(tempString))
parent = m_items.value(tempString);
else {
QTreeWidgetItem *item;
if (parent)
item = new QTreeWidgetItem(parent, QStringList(list.at(l)));
else
item = new QTreeWidgetItem(m_treeWidget, QStringList(list.at(l)));
QFileInfo fi(m_workingDir + "/" + tempString);
if (fi.isDir()) item->setIcon(0, folderIcon);
item->setCheckState(0, m_folderOnly ? Qt::Unchecked : Qt::Checked);
item->setData(0, Qt::UserRole, tempString);
item->setData(0, Qt::UserRole + 1, true);
if (parent) parent->insertChild(0, item);
m_items[tempString] = item;
parent = item;
}
}
}
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::addModifiedItem(const QString &relativePath) {
// Split the string in order to recreate the hierarchy
QStringList list = relativePath.split(QRegExp("\\\\|/"));
QTreeWidgetItem *parent = 0;
QString tempString = "";
QBrush brush(Qt::red);
QIcon folderIcon = QIcon(":Resources/vcfolder_close.png");
int levelCount = list.count();
for (int i = 0; i < levelCount; i++) {
i == 0 ? tempString.append(list.at(i))
: tempString.append("/" + list.at(i));
if (m_items.contains(tempString))
parent = m_items.value(tempString);
else {
QTreeWidgetItem *item;
if (parent)
item = new QTreeWidgetItem(parent, QStringList(list.at(i)));
else
item = new QTreeWidgetItem(m_treeWidget, QStringList(list.at(i)));
QFileInfo fi(m_workingDir + "/" + tempString);
if (fi.isDir()) item->setIcon(0, folderIcon);
item->setCheckState(0, Qt::Checked);
item->setForeground(0, brush);
item->setData(0, Qt::UserRole, tempString);
item->setData(0, Qt::UserRole + 1, false);
m_treeWidget->addTopLevelItem(item);
m_items[tempString] = item;
parent = item;
}
}
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onItemChanged(QTreeWidgetItem *item) {
disconnect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this,
SLOT(onItemChanged(QTreeWidgetItem *)));
Qt::CheckState state = item->checkState(0);
QList<QTreeWidgetItem *> list = m_treeWidget->selectedItems();
for (int i = 0; i < list.count(); i++) {
QTreeWidgetItem *selItem = list.at(i);
if (selItem != item && !selItem->data(0, Qt::CheckStateRole).isNull())
selItem->setCheckState(0, state);
}
connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this,
SLOT(onItemChanged(QTreeWidgetItem *)));
updateTreeSelectionLabel();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onSelectionCheckBoxClicked(bool checked) {
QMapIterator<QString, QTreeWidgetItem *> i(m_items);
int totalCount = 0;
while (i.hasNext()) {
i.next();
QTreeWidgetItem *item = i.value();
if (item && !item->data(0, Qt::CheckStateRole).isNull()) {
totalCount++;
item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked);
}
}
m_selectionLabel->setText(tr("%1 Selected / %2 Total")
.arg(checked ? totalCount : 0)
.arg(totalCount));
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::updateTreeSelectionLabel() {
int totalCount = 0;
int selectedCount = 0;
QMapIterator<QString, QTreeWidgetItem *> i(m_items);
while (i.hasNext()) {
i.next();
QTreeWidgetItem *item = i.value();
if (item && !item->data(0, Qt::CheckStateRole).isNull()) {
totalCount++;
if (item->checkState(0) == Qt::Checked) selectedCount++;
}
}
m_selectionLabel->setText(
tr("%1 Selected / %2 Total").arg(selectedCount).arg(totalCount));
m_commitButton->setEnabled(selectedCount != 0);
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onError(const QString &errorString) {
if (m_targetTempFile) {
QFile::remove(m_targetTempFile->fileName());
delete m_targetTempFile;
m_targetTempFile = 0;
}
m_textLabel->show();
m_textLabel->setText(errorString);
switchToCloseButton();
update();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::initTreeWidget() {
int filesSize = m_filesToPut.size();
bool itemAdded = false;
for (int i = 0; i < filesSize; i++) {
QString fileName = m_filesToPut.at(i);
TFilePath fp =
TFilePath(m_workingDir.toStdWString()) + fileName.toStdWString();
TFilePathSet fpset;
TXshSimpleLevel::getFiles(fp, fpset);
QStringList linkedFiles;
TFilePathSet::iterator it;
for (it = fpset.begin(); it != fpset.end(); ++it) {
QString fn = toQString((*it).withoutParentDir());
if (m_filesToPut.contains(fn)) linkedFiles.append(fn);
}
if (!linkedFiles.isEmpty()) {
itemAdded = true;
QTreeWidgetItem *twi = new QTreeWidgetItem(m_treeWidget);
twi->setText(0, fileName);
twi->setFirstColumnSpanned(false);
twi->setFlags(Qt::NoItemFlags);
for (int i = 0; i < linkedFiles.size(); i++) {
QTreeWidgetItem *child = new QTreeWidgetItem(twi);
child->setText(0, linkedFiles.at(i));
child->setFlags(Qt::NoItemFlags);
}
twi->setExpanded(true);
}
}
if (itemAdded) m_treeWidget->show();
}
//-----------------------------------------------------------------------------
void SVNCommitDialog::onCommiSceneContentsToggled(bool checked) {
if (!checked) {
m_sceneResourcesToCommit.clear();
} else {
VersionControl *vc = VersionControl::instance();
int fileSize = m_filesToPut.count();
for (int i = 0; i < fileSize; i++) {
QString fileName = m_filesToPut.at(i);
if (fileName.endsWith(".tnz")) {
QStringList sceneContents =
vc->getSceneContents(m_workingDir, fileName);
QDir workingDir(m_workingDir);
for (int s = 0; s < sceneContents.size(); s++) {
QString resource = sceneContents.at(s);
QString relativePath = workingDir.relativeFilePath(resource);
m_sceneResourcesToCommit.append(relativePath);
}
}
}
}
m_textLabel->setText(tr("%1 items to put.")
.arg(m_filesToPut.size() +
m_sceneResourcesToCommit.size() -
m_sceneIconAdded));
}
//=============================================================================
// SVNCommitFrameRangeDialog
//-----------------------------------------------------------------------------
SVNCommitFrameRangeDialog::SVNCommitFrameRangeDialog(QWidget *parent,
const QString &workingDir,
const QString &file)
: Dialog(TApp::instance()->getMainWindow(), true, false)
, m_workingDir(workingDir)
, m_file(file)
, m_hasError(false)
, m_hookFileName(QString())
, m_newHookFileName(QString())
, m_isOVLLevel(false) {
setModal(false);
setAttribute(Qt::WA_DeleteOnClose, true);
setWindowTitle(tr("Version Control: Put"));
setMinimumSize(300, 150);
QWidget *container = new QWidget;
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->setAlignment(Qt::AlignHCenter);
mainLayout->setMargin(0);
QHBoxLayout *hLayout = new QHBoxLayout;
m_waitingLabel = new QLabel;
QMovie *waitingMove = new QMovie(":Resources/waiting.gif");
waitingMove->setParent(this);
m_waitingLabel->hide();
m_waitingLabel->setMovie(waitingMove);
waitingMove->setCacheMode(QMovie::CacheAll);
waitingMove->start();
m_textLabel = new QLabel;
m_textLabel->setText(tr("Note: the file will be updated too."));
hLayout->addStretch();
hLayout->addWidget(m_waitingLabel);
hLayout->addWidget(m_textLabel);
hLayout->addStretch();
mainLayout->addLayout(hLayout);
mainLayout->addSpacing(10);
QHBoxLayout *commentLayout = new QHBoxLayout;
m_commentTextEdit = new QPlainTextEdit;
m_commentTextEdit->setMaximumHeight(50);
m_commentLabel = new QLabel(tr("Comment:"));
m_commentLabel->setFixedWidth(55);
commentLayout->addWidget(m_commentLabel, Qt::AlignTop);
commentLayout->addWidget(m_commentTextEdit);
mainLayout->addLayout(commentLayout);
container->setLayout(mainLayout);
beginHLayout();
addWidget(container, false);
endHLayout();
// Check if the hook file still exist
TFilePath path =
TFilePath(m_workingDir.toStdWString()) + m_file.toStdWString();
TFilePath hookFile = TXshSimpleLevel::getExistingHookFile(path);
if (!hookFile.isEmpty())
m_hookFileName =
QString::fromStdWString(hookFile.withoutParentDir().getWideString());
m_isOVLLevel = path.getDots() == "..";
m_commitButton = new QPushButton(tr("Put"));
connect(m_commitButton, SIGNAL(clicked()), this, SLOT(onPutButtonClicked()));
m_cancelButton = new QPushButton(tr("Cancel"));
connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
addButtonBarWidget(m_commitButton, m_cancelButton);
// 0. Connect for svn errors (that may occurs)
connect(&m_thread, SIGNAL(error(const QString &)), this,
SLOT(onError(const QString &)));
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onCommitDone() {
m_waitingLabel->hide();
m_textLabel->setText(tr("Put done successfully."));
QStringList files;
files.append(m_file);
emit done(files);
switchToCloseButton();
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onUpdateDone() {
// Load Level
m_scene = new ToonzScene();
TFilePath levelPath =
TFilePath(m_workingDir.toStdWString()) + m_file.toStdWString();
m_level = m_scene->loadLevel(levelPath);
m_textLabel->setText(tr("Locking file..."));
if (m_isOVLLevel && m_hookFileName.isEmpty()) {
onLockDone();
return;
}
// Step 2: Lock
QStringList args;
args << "lock";
if (!m_isOVLLevel) args << m_file;
if (!m_hookFileName.isEmpty()) args << m_hookFileName;
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), this, SLOT(onLockDone()));
m_thread.executeCommand(m_workingDir, "svn", args, false);
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onLockDone() {
m_textLabel->setText(tr("Getting frame range edit information..."));
if (m_isOVLLevel) {
onPropSetDone();
return;
}
// Step 3: propget
QStringList args;
args << "propget";
args << "partial-lock";
args << m_file;
args << "--xml";
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), this,
SLOT(onPropGetDone(const QString &)));
m_thread.executeCommand(m_workingDir, "svn", args, true);
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onError(const QString &text) {
m_textLabel->setText(text);
switchToCloseButton();
update();
m_hasError = true;
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onPropGetDone(const QString &xmlResponse) {
SVNPartialLockReader reader(xmlResponse);
QList<SVNPartialLock> lockList = reader.getPartialLock();
if (lockList.isEmpty()) {
m_textLabel->setText(tr("No frame range edited."));
switchToCloseButton();
return;
} else {
m_lockInfos = lockList.at(0).m_partialLockList;
if (m_lockInfos.isEmpty()) {
m_textLabel->setText(tr("No frame range edited."));
switchToCloseButton();
return;
}
}
QString partialLockString;
QString userName = VersionControl::instance()->getUserName();
QString hostName = QHostInfo::localHostName();
int count = m_lockInfos.size();
int entryAdded = 0;
for (int i = 0; i < count; i++) {
SVNPartialLockInfo lockInfo = m_lockInfos.at(i);
bool isMe =
lockInfo.m_userName == userName && lockInfo.m_hostName == hostName;
if (!isMe) {
if (i != 0) partialLockString.append(";");
partialLockString.append(lockInfo.m_userName + "@" + lockInfo.m_hostName +
":" + QString::number(lockInfo.m_from) + ":" +
QString::number(lockInfo.m_to));
entryAdded++;
} else
m_myInfo = lockInfo;
}
m_textLabel->setText(tr("Updating frame range edit information..."));
// There is no more partial-lock > propdel
if (entryAdded == 0) {
// Step 4: propdel
QStringList args;
args << "propdel";
args << "partial-lock";
args << m_file;
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), this,
SLOT(onPropSetDone()));
m_thread.executeCommand(m_workingDir, "svn", args, true);
}
// Set the partial-lock property
else {
// Step 4: propset
QStringList args;
args << "propset";
args << "partial-lock";
args << partialLockString;
args << m_file;
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), this,
SLOT(onPropSetDone()));
m_thread.executeCommand(m_workingDir, "svn", args, true);
}
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onPropSetDone() {
m_textLabel->setText(tr("Putting changes..."));
// Merge Level
TFilePath levelPath =
TFilePath(m_workingDir.toStdWString()) + m_file.toStdWString();
// OVL level could only merge the temporary hook file (if exist)
if (m_isOVLLevel) {
QDir dir(m_workingDir);
dir.setNameFilters(QStringList("*.xml"));
QStringList list = dir.entryList(QDir::Files | QDir::Hidden);
int listCount = list.size();
if (listCount > 0) {
QString prefix = QString::fromStdWString(levelPath.getWideName()) + "_" +
VersionControl::instance()->getUserName() + "_" +
TSystem::getHostName();
QString tempFile;
QString hookFileName;
for (int i = 0; i < listCount; i++) {
QString str = list.at(i);
if (str.startsWith(prefix)) {
hookFileName = str;
tempFile = QString(hookFileName);
tempFile.remove("_hooks");
break;
}
}
QStringList temp = tempFile.split("_");
if (temp.size() >= 4) {
QString frameRangeString = temp.at(3);
frameRangeString = frameRangeString.left(frameRangeString.indexOf("."));
QStringList rangeString = frameRangeString.split("-");
if (rangeString.size() == 2) {
TFilePath hookFile =
levelPath.getParentDir() + hookFileName.toStdWString();
// Merge and then delete temporary hook file
if (TFileStatus(hookFile).doesExist()) {
m_level->getSimpleLevel()->mergeTemporaryHookFile(
rangeString.at(0).toInt() - 1, rangeString.at(1).toInt() - 1,
hookFile);
TSystem::removeFileOrLevel(hookFile);
}
m_level->setDirtyFlag(true);
m_level->save();
delete m_scene;
m_scene = 0;
}
}
}
} else {
m_level->getSimpleLevel()->setEditableRange(
m_myInfo.m_from - 1, m_myInfo.m_to - 1,
m_myInfo.m_userName.toStdWString());
m_level->setDirtyFlag(true);
m_level->save();
delete m_scene;
m_scene = 0;
// Delete temporary file
QString tempFileName = QString::fromStdWString(levelPath.getWideName()) +
"_" + m_myInfo.m_userName + "_" +
m_myInfo.m_hostName + "_" +
QString::number(m_myInfo.m_from) + "-" +
QString::number(m_myInfo.m_to) + "." +
QString::fromStdString(levelPath.getType());
TFilePath pathToRemove =
TFilePath(levelPath.getParentDir() + tempFileName.toStdWString());
if (TSystem::doesExistFileOrLevel(pathToRemove))
TSystem::removeFileOrLevel(pathToRemove);
if (pathToRemove.getType() == "tlv") {
pathToRemove = pathToRemove.withType("tpl");
if (TSystem::doesExistFileOrLevel(pathToRemove))
TSystem::removeFileOrLevel(pathToRemove);
}
// Delete temporary hook file
TFilePath hookFilePath = TXshSimpleLevel::getHookPath(pathToRemove);
if (TSystem::doesExistFileOrLevel(hookFilePath))
TSystem::removeFileOrLevel(hookFilePath);
}
// If, after saving the level, a new hook file has been created (and
// previously there isn't an hook file)
// we have to add the new hook file to the repository and set its needs-lock
// property before committing
if (m_hookFileName.isEmpty()) {
// Check if a new hook file exist
TFilePath path =
TFilePath(m_workingDir.toStdWString()) + m_file.toStdWString();
TFilePath hookFile = TXshSimpleLevel::getHookPath(path);
if (TFileStatus(hookFile).doesExist()) {
m_newHookFileName =
QString::fromStdWString(hookFile.withoutParentDir().getWideString());
m_textLabel->setText(tr("Adding hook file to repository..."));
// Step 4a: Add hookFile to repository
QStringList args;
args << "add";
args << "--parents";
args << m_newHookFileName;
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), this,
SLOT(onHookFileAdded()));
m_thread.executeCommand(m_workingDir, "svn", args, true);
} else
commit();
} else
commit();
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onHookFileAdded() {
m_textLabel->setText(tr("Setting the needs-lock property to hook file..."));
// Step 4b: set needs-lock property
QStringList args;
args << "propset"
<< "svn:needs-lock"
<< "'*'";
args << m_newHookFileName;
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), SLOT(commit()));
m_thread.executeCommand(m_workingDir, "svn", args);
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::commit() {
m_textLabel->setText(tr("Putting changes..."));
// Explode, if needed the m_file (OVL)
TFilePath path =
TFilePath(m_workingDir.toStdWString()) + m_file.toStdWString();
if (path.getDots() == "..") {
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);
m_filesToCommit = list.filter(regExp);
} else
m_filesToCommit = QStringList(m_file);
// Add also hook file name (if needed)
if (!m_hookFileName.isEmpty())
m_filesToCommit.append(m_hookFileName);
else if (!m_newHookFileName.isEmpty())
m_filesToCommit.append(m_newHookFileName);
// Step 5: commit
QStringList args;
args << "commit";
int size = m_filesToCommit.size();
for (int i = 0; i < size; i++) args << m_filesToCommit.at(i);
// Comment
if (!m_commentTextEdit->toPlainText().isEmpty())
args << QString("-m").append(m_commentTextEdit->toPlainText());
else
args << QString("-m").append(VersionControl::instance()->getUserName() +
" commit changes.");
m_thread.disconnect(SIGNAL(done(const QString &)));
connect(&m_thread, SIGNAL(done(const QString &)), this, SLOT(onCommitDone()));
m_thread.executeCommand(m_workingDir, "svn", args, true);
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::onPutButtonClicked() {
m_commentLabel->hide();
m_commentTextEdit->hide();
m_waitingLabel->show();
m_textLabel->setText(tr("Updating file..."));
if (m_isOVLLevel && m_hookFileName.isEmpty()) {
onUpdateDone();
return;
}
// Step 1: Update
QStringList args;
args << "update";
if (!m_isOVLLevel) args << m_file;
if (!m_hookFileName.isEmpty()) args << m_hookFileName;
connect(&m_thread, SIGNAL(done(const QString &)), this, SLOT(onUpdateDone()));
m_thread.executeCommand(m_workingDir, "svn", args, false);
}
//-----------------------------------------------------------------------------
void SVNCommitFrameRangeDialog::switchToCloseButton() {
m_waitingLabel->hide();
m_commitButton->disconnect();
m_commitButton->setText("Close");
m_commitButton->setEnabled(true);
m_commitButton->show();
m_cancelButton->hide();
connect(m_commitButton, SIGNAL(clicked()), this, SLOT(close()));
}
//-----------------------------------------------------------------------------