Commit 2f917006 authored by Nikolai Krasheninnikov's avatar Nikolai Krasheninnikov
Browse files

[svn] Added SVN Checkout dialog.

Summary:
{F8293246}
Added SVN Checkout dialog with basic and most commonly used SVN Checkout functionality:
- set repo URL;
- change working copy path;
- omit externals.
Additional features:
- automatically pasting repo URL on dialog creation (if its valid);
- automatically forming working copy path based on repo URL (trying to predict repository name);
- user can pick an output folder instead of typing in;
- few error-controls to prevent running 'svn co' with invalid params (disabling 'OK' button).
SVN Checkout can be time consuming.

Reviewers: #vdg, #dolphin, meven, elvisangelaccio, ngraham

Reviewed By: #dolphin, meven, elvisangelaccio

Subscribers: anthonyfieroni

Differential Revision: https://phabricator.kde.org/D29489
parent b0717f10
......@@ -7,9 +7,10 @@ set(fileviewsvnplugin_SRCS
svncommands.cpp
svncommitdialog.cpp
svnlogdialog.cpp
svncheckoutdialog.cpp
)
ki18n_wrap_ui(fileviewsvnplugin_SRCS svnlogdialog.ui)
ki18n_wrap_ui(fileviewsvnplugin_SRCS svnlogdialog.ui svncheckoutdialog.ui)
kconfig_add_kcfg_files(fileviewsvnplugin_SRCS
fileviewsvnpluginsettings.kcfgc
......
......@@ -46,6 +46,8 @@
#include "svncommitdialog.h"
#include "svnlogdialog.h"
#include "svncheckoutdialog.h"
#include "svncommands.h"
K_PLUGIN_FACTORY(FileViewSvnPluginFactory, registerPlugin<FileViewSvnPlugin>();)
......@@ -118,10 +120,15 @@ FileViewSvnPlugin::FileViewSvnPlugin(QObject* parent, const QList<QVariant>& arg
m_showUpdatesAction, &QAction::setChecked);
m_logAction = new QAction(this);
m_logAction->setText(xi18nc("@action:inmenu", "SVN Log..."));
m_logAction->setText(i18nc("@action:inmenu", "SVN Log..."));
connect(m_logAction, &QAction::triggered,
this, &FileViewSvnPlugin::logDialog);
m_checkoutAction = new QAction(this);
m_checkoutAction->setText(i18nc("@action:inmenu", "SVN Checkout..."));
connect(m_checkoutAction, &QAction::triggered,
this, &FileViewSvnPlugin::checkoutDialog);
connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &FileViewSvnPlugin::slotOperationCompleted);
connect(&m_process, &QProcess::errorOccurred,
......@@ -324,9 +331,14 @@ QList<QAction*> FileViewSvnPlugin::versionControlActions(const KFileItemList& it
QList<QAction*> FileViewSvnPlugin::outOfVersionControlActions(const KFileItemList& items) const
{
Q_UNUSED(items)
// Only for a single directory.
if (items.count() != 1 || !items.first().isDir()) {
return {};
}
return {};
m_contextDir = items.first().localPath();
return QList<QAction*>{} << m_checkoutAction;
}
void FileViewSvnPlugin::updateFiles()
......@@ -448,6 +460,18 @@ void FileViewSvnPlugin::logDialog()
svnLogDialog->show();
}
void FileViewSvnPlugin::checkoutDialog()
{
SvnCheckoutDialog *svnCheckoutDialog = new SvnCheckoutDialog(m_contextDir);
connect(svnCheckoutDialog, &SvnCheckoutDialog::infoMessage, this, &FileViewSvnPlugin::infoMessage);
connect(svnCheckoutDialog, &SvnCheckoutDialog::errorMessage, this, &FileViewSvnPlugin::errorMessage);
connect(svnCheckoutDialog, &SvnCheckoutDialog::operationCompletedMessage, this, &FileViewSvnPlugin::operationCompletedMessage);
svnCheckoutDialog->setAttribute(Qt::WA_DeleteOnClose);
svnCheckoutDialog->show();
}
void FileViewSvnPlugin::slotOperationCompleted(int exitCode, QProcess::ExitStatus exitStatus)
{
m_pendingOperation = false;
......
......@@ -63,6 +63,7 @@ private slots:
void removeFiles();
void revertFiles();
void logDialog();
void checkoutDialog();
void slotOperationCompleted(int exitCode, QProcess::ExitStatus exitStatus);
void slotOperationError();
......@@ -116,6 +117,7 @@ private:
QAction* m_revertAction;
QAction* m_showUpdatesAction;
QAction* m_logAction;
QAction* m_checkoutAction;
QString m_command;
QStringList m_arguments;
......
/***************************************************************************
* Copyright (C) 2019-2020 *
* by Nikolai Krasheninnikov <nkrasheninnikov@yandex.ru> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "svncheckoutdialog.h"
#include <QApplication>
#include <QFileDialog>
#include <QClipboard>
#include <QUrl>
#include <QDir>
#include "svncommands.h"
namespace{
// Helper function: removes trailing slashes.
QString rstrip(const QString &str)
{
for (int i = str.size() - 1; i >= 0; --i) {
if (str.at(i) != '/') {
return str.left(i + 1);
}
}
return {};
}
// Helper function: check if path is a valid svn repository URL.
// Information about URL prefix at http://svnbook.red-bean.com/en/1.2/svn-book.html#svn.basic.in-action.wc.tbl-1.
bool isValidSvnRepoUrl(const QString &path)
{
static const QStringList schemes = { "file", "http", "https", "svn", "svn+ssh" };
const QUrl url = QUrl::fromUserInput(path);
return url.isValid() && schemes.contains( url.scheme() );
}
}
SvnCheckoutDialog::SvnCheckoutDialog(const QString& contextDir, QWidget *parent) :
QDialog(parent),
m_dir(contextDir)
{
m_ui.setupUi(this);
/*
* Add actions, establish connections.
*/
connect(m_ui.pbCancel, &QPushButton::clicked, this, &QWidget::close);
QAction *pickDirectory = m_ui.leCheckoutDir->addAction(QIcon::fromTheme("folder"), QLineEdit::TrailingPosition);
connect(pickDirectory, &QAction::triggered, this, [this] () {
const QString dir = QFileDialog::getExistingDirectory(this, i18nc("@title:window", "Choose a directory to checkout"),
QString(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if (!dir.isEmpty()) {
m_ui.leCheckoutDir->setText(dir);
}
} );
/*
* Additional setup.
*/
const QString repoPath = QApplication::clipboard()->text();
if (isValidSvnRepoUrl(repoPath)) {
m_ui.leRepository->setText(repoPath);
} else {
m_ui.leCheckoutDir->setText(m_dir);
}
}
SvnCheckoutDialog::~SvnCheckoutDialog() = default;
void SvnCheckoutDialog::on_leRepository_textChanged(const QString &text)
{
if (isValidSvnRepoUrl(text)) {
const QString stripped = rstrip(text);
// If URL ends with a 'trunk' this is a branch - lets consider upper folder name as an
// extraction path. So for '.../SomeRepo/trunk/' result would be 'SomeRepo'.
int astart = -1;
if (stripped.endsWith("trunk")) {
astart = -2;
}
const QString suffix = QDir::separator() + stripped.section('/', astart, astart);
m_ui.leCheckoutDir->setText(m_dir + suffix);
m_ui.pbOk->setEnabled(true);
} else {
m_ui.pbOk->setEnabled(false);
}
}
void SvnCheckoutDialog::on_pbOk_clicked()
{
const QString &url = m_ui.leRepository->text();
const bool omitExternals = m_ui.cbOmitExternals->isChecked();
const QString &whereto = m_ui.leCheckoutDir->text();
emit infoMessage(i18nc("@info:status", "SVN checkout: checkout in process..."));
if (!SvnCommands::checkoutRepository(url, omitExternals, whereto)) {
emit errorMessage(i18nc("@info:status", "SVN checkout: checkout failed."));
} else {
emit operationCompletedMessage(i18nc("@info:status", "SVN checkout: checkout successful."));
}
close();
}
/***************************************************************************
* Copyright (C) 2020 *
* by Nikolai Krasheninnikov <nkrasheninnikov@yandex.ru> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#ifndef SVNCHECKOUTDIALOG_H
#define SVNCHECKOUTDIALOG_H
#include <QDialog>
#include "ui_svncheckoutdialog.h"
class SvnCheckoutDialog : public QDialog {
Q_OBJECT
public:
SvnCheckoutDialog(const QString& contextDir, QWidget *parent = nullptr);
virtual ~SvnCheckoutDialog() override;
public slots:
void on_leRepository_textChanged(const QString &text);
void on_pbOk_clicked();
signals:
void infoMessage(const QString& msg);
void errorMessage(const QString& msg);
void operationCompletedMessage(const QString& msg);
private:
Ui::SvnCheckoutDialog m_ui;
QString m_dir;
};
#endif // SVNCHECKOUTDIALOG_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SvnCheckoutDialog</class>
<widget class="QWidget" name="SvnCheckoutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>340</width>
<height>180</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>SVN Checkout</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>URL of repository:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leRepository"/>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Checkout directory:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leCheckoutDir"/>
</item>
<item>
<widget class="QCheckBox" name="cbOmitExternals">
<property name="text">
<string>Omit externals</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>148</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pbOk">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>OK</string>
</property>
<property name="icon">
<iconset theme="dialog-ok">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbCancel">
<property name="text">
<string>Cancel</string>
</property>
<property name="icon">
<iconset theme="dialog-cancel">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
......@@ -403,3 +403,24 @@ QSharedPointer< QVector<logEntry> > SvnCommands::getLog(const QString& filePath,
return log;
}
bool SvnCommands::checkoutRepository(const QString& url, bool ignoreExternals, const QString& whereto)
{
QStringList params;
params.append(QStringLiteral("checkout"));
params.append(url);
if (ignoreExternals) {
params.append(QStringLiteral("--ignore-externals"));
}
params.append(whereto);
QProcess process;
process.start(QLatin1String("svn"), params);
// Without timeout because it could be expensive time consuming operation.
if (!process.waitForFinished(-1) || process.exitCode() != 0) {
return false;
} else {
return true;
}
}
......@@ -161,6 +161,16 @@ public:
* \note This function is really time consuming.
*/
static QSharedPointer< QVector<logEntry> > getLog(const QString& filePath, uint maxEntries = 255, ulong fromRevision = 0);
/**
* Check out a working copy of repository \p URL (local URL starts with a 'file://') to a local
* path \p whereto (could be relative ot absolute).
*
* \return True if check out success, false either.
*
* \note This function can be really time consuming.
*/
static bool checkoutRepository(const QString& url, bool ignoreExternals, const QString& whereto);
};
#endif // SVNCOMMANDS_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment