File indexing completed on 2024-04-14 05:35:35

0001 /***************************************************************************
0002  *   Copyright (C) 2005-2009 by Rajko Albrecht                             *
0003  *   ral@alwins-world.de                                                   *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0019  ***************************************************************************/
0020 
0021 #include "kdesvnview.h"
0022 #include "settings/kdesvnsettings.h"
0023 #include "svnfrontend/createrepodlg.h"
0024 #include "svnfrontend/dumprepo_impl.h"
0025 #include "svnfrontend/fronthelpers/propertylist.h"
0026 #include "svnfrontend/hotcopydlg_impl.h"
0027 #include "svnfrontend/loaddmpdlg_impl.h"
0028 #include "svnfrontend/maintreewidget.h"
0029 #include "svnfrontend/stopdlg.h"
0030 #include "svnqt/repository.h"
0031 #include "svnqt/svnqttypes.h"
0032 #include "svnqt/url.h"
0033 #include "svnqt/version_check.h"
0034 
0035 #include <QFileInfo>
0036 #include <QMenu>
0037 #include <QProgressBar>
0038 #include <QSplitter>
0039 #include <QTemporaryFile>
0040 #include <QTextBrowser>
0041 
0042 #include <KActionCollection>
0043 #include <KIO/FileCopyJob>
0044 #include <KJobWidgets>
0045 #include <KLocalizedString>
0046 #include <KMessageBox>
0047 
0048 kdesvnView::kdesvnView(KActionCollection *aCollection, QWidget *parent, bool full)
0049     : QWidget(parent)
0050     , svn::repository::RepositoryListener()
0051     , m_Collection(aCollection)
0052     , m_currentUrl()
0053     , m_CacheProgressBar(nullptr)
0054     , m_ReposCancel(false)
0055 {
0056     Q_UNUSED(full);
0057     setFocusPolicy(Qt::StrongFocus);
0058     setupActions();
0059 
0060     m_topLayout = new QVBoxLayout(this);
0061 
0062     m_Splitter = new QSplitter(this);
0063     m_Splitter->setOrientation(Qt::Vertical);
0064 
0065     // m_TreeWidget=new kdesvnfilelist(m_Collection,m_Splitter);
0066     m_TreeWidget = new MainTreeWidget(m_Collection, m_Splitter);
0067 
0068     m_infoSplitter = new QSplitter(m_Splitter);
0069     m_infoSplitter->setOrientation(Qt::Horizontal);
0070     m_infoSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0071     m_LogWindow = new QTextBrowser(m_infoSplitter);
0072     m_LogWindow->setContextMenuPolicy(Qt::CustomContextMenu);
0073     connect(m_LogWindow, &QWidget::customContextMenuRequested, this, &kdesvnView::onCustomLogWindowContextMenuRequested);
0074     Propertylist *pl = new Propertylist(m_infoSplitter);
0075     pl->setCommitchanges(true);
0076     connect(pl, &Propertylist::sigSetProperty, m_TreeWidget, &MainTreeWidget::slotChangeProperties);
0077     connect(m_TreeWidget, &MainTreeWidget::sigProplist, pl, &Propertylist::displayList);
0078     connect(m_TreeWidget, &MainTreeWidget::sigProplist, pl, &Propertylist::displayList);
0079 
0080     m_TreeWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0081 
0082     m_topLayout->addWidget(m_Splitter);
0083     connect(m_TreeWidget, &MainTreeWidget::sigLogMessage, this, &kdesvnView::slotAppendLog);
0084     connect(m_TreeWidget, &MainTreeWidget::changeCaption, this, &kdesvnView::slotSetTitle);
0085     connect(m_TreeWidget, &MainTreeWidget::sigShowPopup, this, &kdesvnView::slotDispPopup);
0086     connect(m_TreeWidget, &MainTreeWidget::sigUrlOpened, this, &kdesvnView::sigUrlOpened);
0087     connect(m_TreeWidget, &MainTreeWidget::sigSwitchUrl, this, &kdesvnView::sigSwitchUrl);
0088     connect(m_TreeWidget, &MainTreeWidget::sigUrlChanged, this, &kdesvnView::slotUrlChanged);
0089     connect(m_TreeWidget, &MainTreeWidget::sigCacheStatus, this, &kdesvnView::fillCacheStatus);
0090     connect(m_TreeWidget, &MainTreeWidget::sigExtraStatusMessage, this, &kdesvnView::sigExtraStatusMessage);
0091 
0092     connect(this, &kdesvnView::sigMakeBaseDirs, m_TreeWidget, &MainTreeWidget::slotMkBaseDirs);
0093 
0094     KConfigGroup cs(Kdesvnsettings::self()->config(), "kdesvn-mainlayout");
0095     QByteArray t1 = cs.readEntry("split1", QByteArray());
0096     if (!t1.isEmpty()) {
0097         m_Splitter->restoreState(t1);
0098     }
0099     if (m_infoSplitter) {
0100         t1 = cs.readEntry("infosplit", QByteArray());
0101         if (!t1.isEmpty()) {
0102             m_infoSplitter->restoreState(t1);
0103         }
0104     }
0105 }
0106 
0107 void kdesvnView::slotAppendLog(const QString &text)
0108 {
0109     m_LogWindow->append(text);
0110 }
0111 
0112 kdesvnView::~kdesvnView()
0113 {
0114 }
0115 
0116 void kdesvnView::slotSavestate()
0117 {
0118     KConfigGroup cs(Kdesvnsettings::self()->config(), "kdesvn-mainlayout");
0119     cs.writeEntry("split1", m_Splitter->saveState());
0120     if (m_infoSplitter) {
0121         cs.writeEntry("infosplit", m_infoSplitter->saveState());
0122     }
0123 }
0124 
0125 void kdesvnView::slotUrlChanged(const QUrl &url)
0126 {
0127     m_currentUrl = url;
0128     slotSetTitle(url.toString());
0129     emit sigUrlChanged(url);
0130     slotOnURL(i18n("Repository opened"));
0131 }
0132 
0133 QUrl kdesvnView::currentUrl() const
0134 {
0135     return m_currentUrl;
0136 }
0137 
0138 bool kdesvnView::openUrl(const QUrl &url)
0139 {
0140     /* transform of url must be done in part! otherwise we will run into different troubles! */
0141     m_currentUrl.clear();
0142     QUrl _url(url);
0143     bool open = false;
0144     if (_url.isLocalFile()) {
0145         QString query = _url.query();
0146         _url.setQuery(QString());
0147         QString _f = _url.path();
0148         QFileInfo f(_f);
0149         if (!f.isDir()) {
0150             m_currentUrl.clear();
0151             return open;
0152         }
0153         if (query.length() > 1) {
0154             _url.setQuery(query);
0155         }
0156     } else {
0157         if (!svn::Url::isValid(url.scheme())) {
0158             return open;
0159         }
0160     }
0161     m_LogWindow->clear();
0162     slotSetTitle(url.toString());
0163     if (m_TreeWidget->openUrl(url)) {
0164         slotOnURL(i18n("Repository opened"));
0165         m_currentUrl = url;
0166         open = true;
0167     } else {
0168         QString t = m_TreeWidget->lastError();
0169         if (t.isEmpty()) {
0170             t = i18n("Could not open repository");
0171         }
0172         slotOnURL(t);
0173     }
0174     return open;
0175 }
0176 
0177 void kdesvnView::slotOnURL(const QString &url)
0178 {
0179     emit signalChangeStatusbar(url);
0180 }
0181 
0182 void kdesvnView::slotSetTitle(const QString &title)
0183 {
0184     // emit signalChangeCaption(title);
0185     emit setWindowCaption(title);
0186 }
0187 
0188 /*!
0189     \fn kdesvnView::closeMe()
0190  */
0191 void kdesvnView::closeMe()
0192 {
0193     m_TreeWidget->closeMe();
0194     m_LogWindow->clear();
0195     slotOnURL(i18n("No repository open"));
0196 }
0197 
0198 void kdesvnView::slotDispPopup(const QString &item, QWidget **target)
0199 {
0200     emit sigShowPopup(item, target);
0201 }
0202 
0203 /*!
0204     \fn kdesvnView::refreshCurrentTree()
0205  */
0206 void kdesvnView::refreshCurrentTree()
0207 {
0208     m_TreeWidget->refreshCurrentTree();
0209 }
0210 
0211 /*!
0212     \fn kdesvnView::slotSettingsChanged()
0213  */
0214 void kdesvnView::slotSettingsChanged()
0215 {
0216     m_TreeWidget->slotSettingsChanged();
0217 }
0218 
0219 /*!
0220     \fn kdesvnView::slotCreateRepo()
0221  */
0222 void kdesvnView::slotCreateRepo()
0223 {
0224     QPointer<CreaterepoDlg> dlg(new CreaterepoDlg(this));
0225     if (dlg->exec() != QDialog::Accepted) {
0226         delete dlg;
0227         return;
0228     }
0229     QScopedPointer<svn::repository::Repository> _rep(new svn::repository::Repository(this));
0230     bool ok = true;
0231     closeMe();
0232     try {
0233         _rep->CreateOpen(dlg->parameter());
0234     } catch (const svn::ClientException &e) {
0235         slotAppendLog(e.msg());
0236         ok = false;
0237     }
0238     if (!ok) {
0239         delete dlg;
0240         return;
0241     }
0242     bool createdirs = dlg->createMain();
0243     // repo is created on a local path
0244     const QUrl path = QUrl::fromLocalFile(dlg->targetDir());
0245     delete dlg;
0246     openUrl(path);
0247     if (createdirs) {
0248         emit sigMakeBaseDirs();
0249     }
0250 }
0251 
0252 void kdesvnView::slotHotcopy()
0253 {
0254     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("hotcopy_repo_size"), QApplication::activeModalWidget()));
0255     dlg->setWindowTitle(i18nc("@title:window", "Hotcopy a Repository"));
0256     dlg->setWithCancelButton();
0257 
0258     HotcopyDlg_impl *ptr = new HotcopyDlg_impl(dlg);
0259     dlg->addWidget(ptr);
0260     if (dlg->exec() != QDialog::Accepted) {
0261         delete dlg;
0262         return;
0263     }
0264     bool cleanlogs = ptr->cleanLogs();
0265     QString src = ptr->srcPath();
0266     QString dest = ptr->destPath();
0267     delete dlg;
0268     if (src.isEmpty() || dest.isEmpty()) {
0269         return;
0270     }
0271     try {
0272         svn::repository::Repository::hotcopy(src, dest, cleanlogs);
0273         slotAppendLog(i18n("Hotcopy finished."));
0274     } catch (const svn::ClientException &e) {
0275         slotAppendLog(e.msg());
0276     }
0277 }
0278 
0279 void kdesvnView::slotLoaddump()
0280 {
0281     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("loaddump_repo_size"), this));
0282     dlg->setWindowTitle(i18nc("@title:window", "Load a Repository From an svndump"));
0283     dlg->setWithCancelButton();
0284 
0285     LoadDmpDlg_impl *ptr(new LoadDmpDlg_impl(dlg));
0286     dlg->addWidget(ptr);
0287     if (dlg->exec() != QDialog::Accepted) {
0288         delete dlg;
0289         return;
0290     }
0291     svn::repository::Repository _rep(this);
0292     m_ReposCancel = false;
0293 
0294     try {
0295         _rep.Open(ptr->repository());
0296     } catch (const svn::ClientException &e) {
0297         slotAppendLog(e.msg());
0298         return;
0299     }
0300 
0301     svn::repository::Repository::LOAD_UUID _act;
0302     switch (ptr->uuidAction()) {
0303     case 1:
0304         _act = svn::repository::Repository::UUID_IGNORE_ACTION;
0305         break;
0306     case 2:
0307         _act = svn::repository::Repository::UUID_FORCE_ACTION;
0308         break;
0309     case 0:
0310     default:
0311         _act = svn::repository::Repository::UUID_DEFAULT_ACTION;
0312         break;
0313     }
0314 
0315     const QUrl _uri = ptr->dumpFile();
0316     QString _input;
0317     QTemporaryFile tmpfile;
0318     if (_uri.isLocalFile()) {
0319         _input = _uri.toLocalFile();
0320     } else {
0321         tmpfile.open();
0322         KIO::FileCopyJob *job = KIO::file_copy(_uri, QUrl::fromLocalFile(tmpfile.fileName()));
0323         KJobWidgets::setWindow(job, this);
0324         if (!job->exec()) {
0325             KMessageBox::error(this, job->errorString());
0326             return;
0327         }
0328         _input = tmpfile.fileName();
0329     }
0330 
0331     try {
0332         StopDlg sdlg(nullptr, this, i18nc("@title:window", "Load Dump"), i18n("Loading a dump into a repository."));
0333         _rep.loaddump(_input, _act, ptr->parentPath(), ptr->usePre(), ptr->usePost(), ptr->validateProps());
0334         slotAppendLog(i18n("Loading dump finished."));
0335     } catch (const svn::ClientException &e) {
0336         slotAppendLog(e.msg());
0337     }
0338     delete dlg;
0339 }
0340 
0341 void kdesvnView::slotDumpRepo()
0342 {
0343     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("dump_repo_size"), QApplication::activeModalWidget()));
0344     dlg->setWindowTitle(i18nc("@title:window", "Dump a Repository"));
0345     dlg->setWithCancelButton();
0346 
0347     DumpRepo_impl *ptr(new DumpRepo_impl(dlg));
0348     dlg->addWidget(ptr);
0349     if (dlg->exec() != QDialog::Accepted) {
0350         delete dlg;
0351         return;
0352     }
0353 
0354     const QString re = ptr->reposPath();
0355     const QString out = ptr->targetFile();
0356     const bool incr = ptr->incremental();
0357     const bool diffs = ptr->use_deltas();
0358     const int s = ptr->startNumber();
0359     const int e = ptr->endNumber();
0360 
0361     delete dlg;
0362 
0363     m_ReposCancel = false;
0364     svn::Revision st = svn::Revision::UNDEFINED;
0365     svn::Revision en = svn::Revision::UNDEFINED;
0366 
0367     if (s > -1) {
0368         st = s;
0369     }
0370     if (e > -1) {
0371         en = e;
0372     }
0373 
0374     svn::repository::Repository *_rep(new svn::repository::Repository(this));
0375     try {
0376         _rep->Open(re);
0377     } catch (const svn::ClientException &e) {
0378         slotAppendLog(e.msg());
0379         delete _rep;
0380         return;
0381     }
0382 
0383     try {
0384         StopDlg sdlg(nullptr, this, i18nc("@title:window", "Dump"), i18n("Dumping a repository"));
0385         _rep->dump(out, st, en, incr, diffs);
0386         slotAppendLog(i18n("Dump finished."));
0387     } catch (const svn::ClientException &e) {
0388         slotAppendLog(e.msg());
0389     }
0390     delete _rep;
0391 }
0392 
0393 /*!
0394     \fn kdesvnView::setupActions()
0395  */
0396 void kdesvnView::setupActions()
0397 {
0398 }
0399 
0400 void kdesvnView::sendWarning(const QString &aMsg)
0401 {
0402     slotAppendLog(aMsg);
0403 }
0404 
0405 void kdesvnView::sendError(const QString &aMsg)
0406 {
0407     slotAppendLog(aMsg);
0408 }
0409 
0410 bool kdesvnView::isCanceld()
0411 {
0412     if (!m_ReposCancel) {
0413         emit tickProgress();
0414         return false;
0415     }
0416     return true;
0417 }
0418 
0419 void kdesvnView::setCanceled(bool how)
0420 {
0421     m_ReposCancel = how;
0422 }
0423 
0424 void kdesvnView::fillCacheStatus(qlonglong current, qlonglong max)
0425 {
0426     if (current > -1 && max > -1) {
0427         if (!m_CacheProgressBar) {
0428             m_CacheProgressBar = new QProgressBar(this);
0429             m_CacheProgressBar->setRange(0, (int)max);
0430             m_topLayout->addWidget(m_CacheProgressBar);
0431             m_CacheProgressBar->setFormat(i18n("Inserted %v not cached log entries of %m."));
0432         }
0433         if (!m_CacheProgressBar->isVisible()) {
0434             m_CacheProgressBar->show();
0435         }
0436         m_CacheProgressBar->setValue((int)current);
0437     } else {
0438         delete m_CacheProgressBar;
0439         m_CacheProgressBar = nullptr;
0440     }
0441 }
0442 
0443 void kdesvnView::stopCacheThreads()
0444 {
0445     m_TreeWidget->stopLogCache();
0446 }
0447 
0448 void kdesvnView::onCustomLogWindowContextMenuRequested(const QPoint &pos)
0449 {
0450     QPointer<QMenu> menu = m_LogWindow->createStandardContextMenu();
0451     QAction *clearAction = new QAction(tr("Clear"), menu.data());
0452     clearAction->setEnabled(!m_LogWindow->toPlainText().isEmpty());
0453     connect(clearAction, &QAction::triggered, m_LogWindow, &QTextEdit::clear);
0454     menu->addAction(clearAction);
0455     menu->exec(m_LogWindow->mapToGlobal(pos));
0456     delete menu;
0457 }
0458 
0459 #include "moc_kdesvnview.cpp"