File indexing completed on 2024-04-28 05:42:02

0001 /***************************************************************************
0002  *   Copyright (C) 2008 by Rajko Albrecht  ral@alwins-world.de             *
0003  *   https://kde.org/applications/development/org.kde.kdesvn               *
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 "maintreewidget.h"
0022 #include "EditIgnorePattern.h"
0023 #include "checkoutinfo_impl.h"
0024 #include "copymoveview_impl.h"
0025 #include "cursorstack.h"
0026 #include "database/dbsettings.h"
0027 #include "fronthelpers/fronthelpers.h"
0028 #include "fronthelpers/rangeinput_impl.h"
0029 #include "fronthelpers/widgetblockstack.h"
0030 #include "helpers/kdesvn_debug.h"
0031 #include "helpers/sshagent.h"
0032 #include "importdir_logmsg.h"
0033 #include "ksvnwidgets/commitmsg_impl.h"
0034 #include "ksvnwidgets/deleteform.h"
0035 #include "mergedlg_impl.h"
0036 #include "models/svndirsortfilter.h"
0037 #include "models/svnitemmodel.h"
0038 #include "models/svnitemnode.h"
0039 #include "models/svnsortfilter.h"
0040 #include "opencontextmenu.h"
0041 #include "settings/kdesvnsettings.h"
0042 #include "svnactions.h"
0043 #include "svnqt/targets.h"
0044 #include "svnqt/url.h"
0045 
0046 #include <KMessageBox>
0047 #include <KMessageBox_KDESvnCompat>
0048 #include <kactioncollection.h>
0049 #include <kapplicationtrader.h>
0050 #include <kauthorized.h>
0051 #include <kio/applicationlauncherjob.h>
0052 #include <kio/copyjob.h>
0053 #include <kio/deletejob.h>
0054 #include <kio/jobuidelegatefactory.h>
0055 #include <kjobuidelegate.h>
0056 #include <kjobwidgets.h>
0057 #include <unistd.h>
0058 
0059 #include <QApplication>
0060 #include <QCheckBox>
0061 #include <QKeyEvent>
0062 #include <QTimer>
0063 #include <QUrlQuery>
0064 
0065 class MainTreeWidgetData
0066 {
0067 public:
0068     MainTreeWidgetData()
0069     {
0070         m_Collection = nullptr;
0071         m_Model = nullptr;
0072         m_SortModel = nullptr;
0073         m_DirSortModel = nullptr;
0074         m_remoteRevision = svn::Revision::UNDEFINED;
0075     }
0076 
0077     ~MainTreeWidgetData()
0078     {
0079         delete m_Model;
0080         delete m_SortModel;
0081         delete m_DirSortModel;
0082     }
0083 
0084     QModelIndex srcInd(const QModelIndex &ind)
0085     {
0086         return m_SortModel->mapToSource(ind);
0087     }
0088 
0089     QModelIndex srcDirInd(const QModelIndex &ind)
0090     {
0091         return m_DirSortModel->mapToSource(ind);
0092     }
0093 
0094     SvnItemModelNode *sourceNode(const QModelIndex &index, bool left)
0095     {
0096         if (!index.isValid()) {
0097             return nullptr;
0098         }
0099         QModelIndex ind = left ? m_DirSortModel->mapToSource(index) : m_SortModel->mapToSource(index);
0100         if (ind.isValid()) {
0101             return static_cast<SvnItemModelNode *>(ind.internalPointer());
0102         }
0103         return nullptr;
0104     }
0105 
0106     KActionCollection *m_Collection;
0107     SvnItemModel *m_Model;
0108     SvnSortFilterProxy *m_SortModel;
0109     SvnDirSortFilterProxy *m_DirSortModel;
0110     svn::Revision m_remoteRevision;
0111     QString merge_Target, merge_Src2, merge_Src1;
0112 
0113     QTimer m_TimeModified, m_TimeUpdates, m_resizeColumnsTimer;
0114 };
0115 
0116 MainTreeWidget::MainTreeWidget(KActionCollection *aCollection, QWidget *parent, Qt::WindowFlags f)
0117     : QWidget(parent, f)
0118     , m_Data(new MainTreeWidgetData)
0119 {
0120     setupUi(this);
0121     setFocusPolicy(Qt::StrongFocus);
0122     m_TreeView->setFocusPolicy(Qt::StrongFocus);
0123     m_Data->m_Collection = aCollection;
0124     m_Data->m_SortModel = new SvnSortFilterProxy();
0125     m_Data->m_SortModel->setDynamicSortFilter(true);
0126     m_Data->m_SortModel->setSortRole(SORT_ROLE);
0127     m_Data->m_SortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
0128     m_Data->m_SortModel->sort(0);
0129     m_TreeView->setModel(m_Data->m_SortModel);
0130     m_TreeView->sortByColumn(0, Qt::AscendingOrder);
0131     m_Data->m_Model = new SvnItemModel(this);
0132     m_Data->m_SortModel->setSourceModel(m_Data->m_Model);
0133 
0134     m_Data->m_DirSortModel = new SvnDirSortFilterProxy();
0135     m_Data->m_DirSortModel->setDynamicSortFilter(true);
0136     m_Data->m_DirSortModel->setSortRole(SORT_ROLE);
0137     m_Data->m_DirSortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
0138 
0139     m_DirTreeView->setModel(m_Data->m_DirSortModel);
0140     m_Data->m_DirSortModel->setSourceModel(m_Data->m_Model);
0141 
0142     connect(m_TreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainTreeWidget::slotSelectionChanged);
0143 
0144     connect(m_DirTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainTreeWidget::slotDirSelectionChanged);
0145 
0146     connect(m_Data->m_Model->svnWrapper(), &SvnActions::clientException, this, &MainTreeWidget::slotClientException);
0147     connect(m_Data->m_Model, &SvnItemModel::clientException, this, &MainTreeWidget::slotClientException);
0148     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sendNotify, this, &MainTreeWidget::slotNotifyMessage);
0149     connect(m_Data->m_Model->svnWrapper(), &SvnActions::reinitItem, this, &MainTreeWidget::slotReinitItem);
0150     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigRefreshAll, this, &MainTreeWidget::refreshCurrentTree);
0151     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigRefreshCurrent, this, &MainTreeWidget::refreshCurrent);
0152     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigRefreshItem, this, &MainTreeWidget::slotRefreshItem);
0153     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigGotourl, this, &MainTreeWidget::_openUrl);
0154     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigCacheStatus, this, &MainTreeWidget::sigCacheStatus);
0155     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigThreadsChanged, this, &MainTreeWidget::enableActions);
0156     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigCacheDataChanged, this, &MainTreeWidget::slotCacheDataChanged);
0157 
0158     connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigExtraStatusMessage, this, &MainTreeWidget::sigExtraStatusMessage);
0159 
0160     connect(m_Data->m_Model, &SvnItemModel::urlDropped, this, &MainTreeWidget::slotUrlDropped);
0161 
0162     connect(m_Data->m_Model, &SvnItemModel::itemsFetched, this, &MainTreeWidget::slotItemsInserted);
0163 
0164     m_TreeView->sortByColumn(0, Qt::AscendingOrder);
0165     m_DirTreeView->sortByColumn(0, Qt::AscendingOrder);
0166 
0167     checkUseNavigation(true);
0168     setupActions();
0169 
0170     m_Data->m_TimeModified.setParent(this);
0171     connect(&(m_Data->m_TimeModified), &QTimer::timeout, this, &MainTreeWidget::slotCheckModified);
0172     m_Data->m_TimeUpdates.setParent(this);
0173     connect(&(m_Data->m_TimeUpdates), &QTimer::timeout, this, &MainTreeWidget::slotCheckUpdates);
0174     m_Data->m_resizeColumnsTimer.setSingleShot(true);
0175     m_Data->m_resizeColumnsTimer.setParent(this);
0176     connect(&(m_Data->m_resizeColumnsTimer), &QTimer::timeout, this, &MainTreeWidget::resizeAllColumns);
0177 }
0178 
0179 MainTreeWidget::~MainTreeWidget()
0180 {
0181     // make sure to not get signals which affect the mmi
0182     m_Data->m_Model->disconnect(this);
0183     m_Data->m_Model->svnWrapper()->disconnect(this);
0184     delete m_Data;
0185 }
0186 
0187 void MainTreeWidget::_openUrl(const QUrl &url)
0188 {
0189     openUrl(url, true);
0190 }
0191 
0192 void MainTreeWidget::resizeAllColumns()
0193 {
0194     m_TreeView->resizeColumnToContents(SvnItemModel::Name);
0195     m_TreeView->resizeColumnToContents(SvnItemModel::Status);
0196     m_TreeView->resizeColumnToContents(SvnItemModel::LastRevision);
0197     m_TreeView->resizeColumnToContents(SvnItemModel::LastAuthor);
0198     m_TreeView->resizeColumnToContents(SvnItemModel::LastDate);
0199     m_DirTreeView->resizeColumnToContents(SvnItemModel::Name);
0200 }
0201 
0202 bool MainTreeWidget::openUrl(const QUrl &url, bool noReinit)
0203 {
0204 #ifdef DEBUG_TIMER
0205     QTime _counttime;
0206     _counttime.start();
0207 #endif
0208 
0209     CursorStack a;
0210     m_Data->m_Model->svnWrapper()->killallThreads();
0211     clear();
0212     emit sigProplist(svn::PathPropertiesMapListPtr(new svn::PathPropertiesMapList()), false, false, QString());
0213 
0214     if (!noReinit) {
0215         m_Data->m_Model->svnWrapper()->reInitClient();
0216     }
0217 
0218     QUrl _url(url);
0219     const QString proto = svn::Url::transformProtokoll(url.scheme());
0220     _url = _url.adjusted(QUrl::StripTrailingSlash | QUrl::NormalizePathSegments);
0221     _url.setScheme(proto);
0222 
0223     const QString baseUriString = _url.url(QUrl::StripTrailingSlash);
0224     const QVector<QStringRef> s = baseUriString.splitRef(QLatin1Char('?'));
0225     if (s.size() > 1) {
0226         setBaseUri(s.first().toString());
0227     } else {
0228         setBaseUri(baseUriString);
0229     }
0230     setWorkingCopy(false);
0231     setNetworked(false);
0232     m_Data->m_remoteRevision = svn::Revision::HEAD;
0233 
0234     if (QLatin1String("svn+file") == url.scheme()) {
0235         setBaseUri(url.path());
0236     } else {
0237         if (url.isLocalFile()) {
0238             QFileInfo fi(url.path());
0239             if (fi.exists() && fi.isSymLink()) {
0240                 const QString sl = fi.symLinkTarget();
0241                 if (sl.startsWith(QLatin1Char('/'))) {
0242                     setBaseUri(sl);
0243                 } else {
0244                     fi.setFile(fi.path() + QLatin1Char('/') + sl);
0245                     setBaseUri(fi.absoluteFilePath());
0246                 }
0247             } else {
0248                 setBaseUri(url.path());
0249             }
0250             QUrl _dummy;
0251             qCDebug(KDESVN_LOG) << "check if " << baseUri() << " is a local wc ...";
0252             if (m_Data->m_Model->svnWrapper()->isLocalWorkingCopy(baseUri(), _dummy)) {
0253                 setWorkingCopy(true);
0254                 // make sure a valid path is stored as baseuri
0255                 setBaseUri(url.toLocalFile());
0256                 qCDebug(KDESVN_LOG) << "... yes -> " << baseUri();
0257             } else {
0258                 setWorkingCopy(false);
0259                 // make sure a valid url is stored as baseuri
0260                 setBaseUri(url.toString());
0261                 qCDebug(KDESVN_LOG) << "... no -> " << baseUri();
0262             }
0263         } else {
0264             setNetworked(true);
0265             if (!Kdesvnsettings::network_on()) {
0266                 setBaseUri(QString());
0267                 setNetworked(false);
0268                 clear();
0269                 KMessageBox::error(this, i18n("Networked URL to open but networking is disabled."));
0270                 emit changeCaption(QString());
0271                 emit sigUrlOpened(false);
0272                 return false;
0273             }
0274         }
0275     }
0276     const QList<QPair<QString, QString>> q = QUrlQuery(url).queryItems();
0277     typedef QPair<QString, QString> queryPair;
0278     for (const queryPair &p : q) {
0279         if (p.first == QLatin1String("rev")) {
0280             const QString v = p.second;
0281             svn::Revision tmp;
0282             m_Data->m_Model->svnWrapper()->svnclient()->url2Revision(v, m_Data->m_remoteRevision, tmp);
0283             if (m_Data->m_remoteRevision == svn::Revision::UNDEFINED) {
0284                 m_Data->m_remoteRevision = svn::Revision::HEAD;
0285             }
0286         }
0287     }
0288     if (url.scheme() == QLatin1String("svn+ssh") || url.scheme() == QLatin1String("ksvn+ssh")) {
0289         SshAgent ssh;
0290         ssh.addSshIdentities();
0291     }
0292     m_Data->m_Model->svnWrapper()->clearUpdateCache();
0293     if (isWorkingCopy()) {
0294         m_Data->m_Model->initDirWatch();
0295     }
0296     bool result = m_Data->m_Model->checkDirs(baseUri(), nullptr) > -1;
0297     if (result && isWorkingCopy()) {
0298         m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
0299         m_DirTreeView->expandToDepth(0);
0300         m_DirTreeView->selectionModel()->select(m_Data->m_DirSortModel->mapFromSource(m_Data->m_Model->firstRootIndex()), QItemSelectionModel::Select);
0301     }
0302     resizeAllColumns();
0303 
0304     if (!result) {
0305         setBaseUri(QString());
0306         setNetworked(false);
0307         clear();
0308     }
0309     if (result && isWorkingCopy()) {
0310         m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
0311         if (Kdesvnsettings::start_updates_check_on_open()) {
0312             slotCheckUpdates();
0313         }
0314     }
0315 #ifdef DEBUG_TIMER
0316     _counttime.restart();
0317 #endif
0318 
0319     if (result && Kdesvnsettings::log_cache_on_open()) {
0320         m_Data->m_Model->svnWrapper()->startFillCache(baseUri(), true);
0321     }
0322 #ifdef DEBUG_TIMER
0323     qCDebug(KDESVN_LOG) << "Starting cache " << _counttime.elapsed();
0324     _counttime.restart();
0325 #endif
0326     emit changeCaption(baseUri());
0327     emit sigUrlOpened(result);
0328     emit sigUrlChanged(baseUriAsUrl());
0329 #ifdef DEBUG_TIMER
0330     qCDebug(KDESVN_LOG) << "Fired signals " << _counttime.elapsed();
0331     _counttime.restart();
0332 #endif
0333 
0334     QTimer::singleShot(1, this, &MainTreeWidget::readSupportData);
0335     enableActions();
0336 #ifdef DEBUG_TIMER
0337     qCDebug(KDESVN_LOG) << "Enabled actions " << _counttime.elapsed();
0338 #endif
0339     /*  KNotification * notification=new KNotification("kdesvn-open");
0340         notification->setText("Opened url");
0341         notification->sendEvent();
0342     */
0343     return result;
0344 }
0345 
0346 void MainTreeWidget::clear()
0347 {
0348     m_Data->m_Model->clear();
0349     m_TreeView->setRootIndex(QModelIndex());
0350 }
0351 
0352 svn::Revision MainTreeWidget::baseRevision() const
0353 {
0354     return m_Data->m_remoteRevision;
0355 }
0356 
0357 QWidget *MainTreeWidget::realWidget()
0358 {
0359     return this;
0360 }
0361 
0362 int MainTreeWidget::selectionCount() const
0363 {
0364     int count = m_TreeView->selectionModel()->selectedRows(0).count();
0365     if (count == 0) {
0366         if (m_TreeView->rootIndex().isValid()) {
0367             return 1;
0368         }
0369     }
0370     return count;
0371 }
0372 
0373 int MainTreeWidget::DirselectionCount() const
0374 {
0375     return m_DirTreeView->selectionModel()->selectedRows(0).count();
0376 }
0377 
0378 SvnItemList MainTreeWidget::SelectionList() const
0379 {
0380     SvnItemList ret;
0381     const QModelIndexList _mi = m_TreeView->selectionModel()->selectedRows(0);
0382     if (_mi.isEmpty()) {
0383         QModelIndex ind = m_TreeView->rootIndex();
0384         if (ind.isValid()) {
0385             // really! it will remapped to this before setRootIndex! (see below)
0386             ret.push_back(m_Data->sourceNode(ind, false));
0387         }
0388         return ret;
0389     }
0390     ret.reserve(_mi.size());
0391     for (const QModelIndex &idx : _mi) {
0392         ret.push_back(m_Data->sourceNode(idx, false));
0393     }
0394     return ret;
0395 }
0396 
0397 SvnItemList MainTreeWidget::DirSelectionList() const
0398 {
0399     SvnItemList ret;
0400     const QModelIndexList _mi = m_DirTreeView->selectionModel()->selectedRows(0);
0401     ret.reserve(_mi.size());
0402     for (const QModelIndex &idx : _mi) {
0403         ret.push_back(m_Data->sourceNode(idx, true));
0404     }
0405     return ret;
0406 }
0407 
0408 QModelIndex MainTreeWidget::SelectedIndex() const
0409 {
0410     const QModelIndexList _mi = m_TreeView->selectionModel()->selectedRows(0);
0411     if (_mi.count() != 1) {
0412         if (_mi.isEmpty()) {
0413             const QModelIndex ind = m_TreeView->rootIndex();
0414             if (ind.isValid()) {
0415                 return m_Data->m_SortModel->mapToSource(ind);
0416             }
0417         }
0418         return QModelIndex();
0419     }
0420     return m_Data->m_SortModel->mapToSource(_mi[0]);
0421 }
0422 
0423 QModelIndex MainTreeWidget::DirSelectedIndex() const
0424 {
0425     const QModelIndexList _mi = m_DirTreeView->selectionModel()->selectedRows(0);
0426     if (_mi.count() != 1) {
0427         return QModelIndex();
0428     }
0429     return m_Data->m_DirSortModel->mapToSource(_mi[0]);
0430 }
0431 
0432 SvnItemModelNode *MainTreeWidget::SelectedNode() const
0433 {
0434     const QModelIndex index = SelectedIndex();
0435     if (index.isValid()) {
0436         SvnItemModelNode *item = static_cast<SvnItemModelNode *>(index.internalPointer());
0437         return item;
0438     }
0439     return nullptr;
0440 }
0441 
0442 SvnItemModelNode *MainTreeWidget::DirSelectedNode() const
0443 {
0444     const QModelIndex index = DirSelectedIndex();
0445     if (index.isValid()) {
0446         SvnItemModelNode *item = static_cast<SvnItemModelNode *>(index.internalPointer());
0447         return item;
0448     }
0449     return nullptr;
0450 }
0451 
0452 void MainTreeWidget::slotSelectionChanged(const QItemSelection &, const QItemSelection &)
0453 {
0454     enableActions();
0455     QTimer::singleShot(100, this, &MainTreeWidget::_propListTimeout);
0456 }
0457 
0458 SvnItem *MainTreeWidget::Selected() const
0459 {
0460     return SelectedNode();
0461 }
0462 
0463 SvnItem *MainTreeWidget::DirSelected() const
0464 {
0465     return DirSelectedNode();
0466 }
0467 
0468 SvnItem *MainTreeWidget::DirSelectedOrMain() const
0469 {
0470     SvnItem *_item = DirSelected();
0471     if (_item == nullptr && isWorkingCopy()) {
0472         _item = m_Data->m_Model->firstRootChild();
0473     }
0474     return _item;
0475 }
0476 
0477 SvnItem *MainTreeWidget::SelectedOrMain() const
0478 {
0479     SvnItem *_item = Selected();
0480     if (_item == nullptr && isWorkingCopy()) {
0481         _item = m_Data->m_Model->firstRootChild();
0482     }
0483     return _item;
0484 }
0485 
0486 void MainTreeWidget::setupActions()
0487 {
0488     if (!m_Data->m_Collection) {
0489         return;
0490     }
0491     QAction *tmp_action;
0492     /* local and remote actions */
0493     /* 1. actions on dirs AND files */
0494     tmp_action = add_action(QStringLiteral("make_svn_log_full"),
0495                             i18n("History of item"),
0496                             QKeySequence(Qt::CTRL | Qt::Key_L),
0497                             QIcon::fromTheme(QStringLiteral("kdesvnlog")),
0498                             this,
0499                             SLOT(slotMakeLog()));
0500     tmp_action->setIconText(i18n("History"));
0501     tmp_action->setStatusTip(i18n("Displays the history log of selected item"));
0502     tmp_action = add_action(QStringLiteral("make_svn_log_nofollow"),
0503                             i18n("History of item ignoring copies"),
0504                             QKeySequence(Qt::SHIFT | Qt::CTRL | Qt::Key_L),
0505                             QIcon::fromTheme(QStringLiteral("kdesvnlog")),
0506                             this,
0507                             SLOT(slotMakeLogNoFollow()));
0508     tmp_action->setIconText(i18n("History"));
0509     tmp_action->setStatusTip(i18n("Displays the history log of selected item without following copies"));
0510 
0511     tmp_action = add_action(QStringLiteral("make_svn_dir_log_nofollow"),
0512                             i18n("History of item ignoring copies"),
0513                             QKeySequence(),
0514                             QIcon::fromTheme(QStringLiteral("kdesvnlog")),
0515                             this,
0516                             SLOT(slotDirMakeLogNoFollow()));
0517     tmp_action->setIconText(i18n("History"));
0518     tmp_action->setStatusTip(i18n("Displays the history log of selected item without following copies"));
0519 
0520     tmp_action = add_action(QStringLiteral("make_svn_tree"),
0521                             i18n("Full revision tree"),
0522                             QKeySequence(Qt::CTRL | Qt::Key_T),
0523                             QIcon::fromTheme(QStringLiteral("kdesvntree")),
0524                             this,
0525                             SLOT(slotMakeTree()));
0526     tmp_action->setStatusTip(i18n("Shows history of item as linked tree"));
0527     tmp_action = add_action(QStringLiteral("make_svn_partialtree"),
0528                             i18n("Partial revision tree"),
0529                             QKeySequence(Qt::SHIFT | Qt::CTRL | Qt::Key_T),
0530                             QIcon::fromTheme(QStringLiteral("kdesvntree")),
0531                             this,
0532                             SLOT(slotMakePartTree()));
0533     tmp_action->setStatusTip(i18n("Shows history of item as linked tree for a revision range"));
0534 
0535     tmp_action =
0536         add_action(QStringLiteral("make_svn_property"), i18n("Properties"), QKeySequence(Qt::CTRL | Qt::Key_P), QIcon(), this, SLOT(slotRightProperties()));
0537     tmp_action = add_action(QStringLiteral("make_left_svn_property"), i18n("Properties"), QKeySequence(), QIcon(), this, SLOT(slotLeftProperties()));
0538     add_action(QStringLiteral("get_svn_property"),
0539                i18n("Display Properties"),
0540                QKeySequence(Qt::SHIFT | Qt::CTRL | Qt::Key_P),
0541                QIcon(),
0542                this,
0543                SLOT(slotDisplayProperties()));
0544     tmp_action = add_action(QStringLiteral("make_last_change"),
0545                             i18n("Display last changes"),
0546                             QKeySequence(),
0547                             QIcon::fromTheme(QStringLiteral("kdesvndiff")),
0548                             this,
0549                             SLOT(slotDisplayLastDiff()));
0550     tmp_action->setToolTip(i18n("Display last changes as difference to previous commit."));
0551     tmp_action = add_action(QStringLiteral("make_svn_info"),
0552                             i18n("Details"),
0553                             QKeySequence(Qt::CTRL | Qt::Key_I),
0554                             QIcon::fromTheme(QStringLiteral("kdesvninfo")),
0555                             this,
0556                             SLOT(slotInfo()));
0557     tmp_action->setStatusTip(i18n("Show details about selected item"));
0558     tmp_action = add_action(QStringLiteral("make_svn_rename"),
0559                             i18n("Move"),
0560                             QKeySequence(Qt::Key_F2),
0561                             QIcon::fromTheme(QStringLiteral("kdesvnmove")),
0562                             this,
0563                             SLOT(slotRename()));
0564     tmp_action->setStatusTip(i18n("Moves or renames current item"));
0565     tmp_action = add_action(QStringLiteral("make_svn_copy"),
0566                             i18n("Copy"),
0567                             QKeySequence(Qt::CTRL | Qt::Key_C),
0568                             QIcon::fromTheme(QStringLiteral("kdesvncopy")),
0569                             this,
0570                             SLOT(slotCopy()));
0571     tmp_action->setStatusTip(i18n("Create a copy of current item"));
0572     tmp_action = add_action(QStringLiteral("make_check_updates"),
0573                             i18n("Check for updates"),
0574                             QKeySequence(),
0575                             QIcon::fromTheme(QStringLiteral("kdesvncheckupdates")),
0576                             this,
0577                             SLOT(slotCheckUpdates()));
0578     tmp_action->setToolTip(i18n("Check if current working copy has items with newer version in repository"));
0579     tmp_action->setStatusTip(tmp_action->toolTip());
0580     tmp_action->setIconText(i18n("Check updates"));
0581 
0582     /* 2. actions only on files */
0583     tmp_action =
0584         add_action(QStringLiteral("make_svn_blame"), i18n("Blame"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnblame")), this, SLOT(slotBlame()));
0585     tmp_action->setToolTip(i18n("Output the content of specified files or URLs with revision and author information in-line."));
0586     tmp_action->setStatusTip(tmp_action->toolTip());
0587     tmp_action = add_action(QStringLiteral("make_svn_range_blame"),
0588                             i18n("Blame range"),
0589                             QKeySequence(),
0590                             QIcon::fromTheme(QStringLiteral("kdesvnblame")),
0591                             this,
0592                             SLOT(slotRangeBlame()));
0593     tmp_action->setToolTip(i18n("Output the content of specified files or URLs with revision and author information in-line."));
0594     tmp_action->setStatusTip(tmp_action->toolTip());
0595 
0596     tmp_action =
0597         add_action(QStringLiteral("make_svn_cat"), i18n("Cat head"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncat")), this, SLOT(slotCat()));
0598     tmp_action->setToolTip(i18n("Output the content of specified files or URLs."));
0599     tmp_action->setStatusTip(tmp_action->toolTip());
0600     tmp_action = add_action(QStringLiteral("make_revisions_cat"),
0601                             i18n("Cat revision..."),
0602                             QKeySequence(),
0603                             QIcon::fromTheme(QStringLiteral("kdesvncat")),
0604                             this,
0605                             SLOT(slotRevisionCat()));
0606     tmp_action->setToolTip(i18n("Output the content of specified files or URLs at specific revision."));
0607     tmp_action->setStatusTip(tmp_action->toolTip());
0608 
0609     tmp_action = add_action(QStringLiteral("make_svn_lock"),
0610                             i18n("Lock current items"),
0611                             QKeySequence(),
0612                             QIcon::fromTheme(QStringLiteral("kdesvnlock")),
0613                             this,
0614                             SLOT(slotLock()));
0615     tmp_action->setToolTip(i18n("Try lock current item against changes from other users"));
0616     tmp_action->setStatusTip(tmp_action->toolTip());
0617     tmp_action = add_action(QStringLiteral("make_svn_unlock"),
0618                             i18n("Unlock current items"),
0619                             QKeySequence(),
0620                             QIcon::fromTheme(QStringLiteral("kdesvnunlock")),
0621                             this,
0622                             SLOT(slotUnlock()));
0623     tmp_action->setToolTip(i18n("Free existing lock on current item"));
0624     tmp_action->setStatusTip(tmp_action->toolTip());
0625 
0626     /* 3. actions only on dirs */
0627     tmp_action = add_action(QStringLiteral("make_svn_mkdir"),
0628                             i18n("New folder"),
0629                             QKeySequence(),
0630                             QIcon::fromTheme(QStringLiteral("kdesvnnewfolder")),
0631                             this,
0632                             SLOT(slotMkdir()));
0633     tmp_action->setStatusTip(i18n("Create a new folder"));
0634     tmp_action = add_action(QStringLiteral("make_svn_switch"),
0635                             i18n("Switch repository"),
0636                             QKeySequence(),
0637                             QIcon::fromTheme(QStringLiteral("kdesvnswitch")),
0638                             m_Data->m_Model->svnWrapper(),
0639                             SLOT(slotSwitch()));
0640     tmp_action->setToolTip(i18n("Switch repository path of current working copy path (\"svn switch\")"));
0641     tmp_action->setStatusTip(tmp_action->toolTip());
0642 
0643     tmp_action = add_action(QStringLiteral("make_svn_relocate"),
0644                             i18n("Relocate current working copy URL"),
0645                             QKeySequence(),
0646                             QIcon::fromTheme(QStringLiteral("kdesvnrelocate")),
0647                             this,
0648                             SLOT(slotRelocate()));
0649     tmp_action->setToolTip(i18n("Relocate URL of current working copy path to other URL"));
0650     tmp_action->setStatusTip(tmp_action->toolTip());
0651 
0652     tmp_action = add_action(QStringLiteral("make_check_unversioned"),
0653                             i18n("Check for unversioned items"),
0654                             QKeySequence(),
0655                             QIcon::fromTheme(QStringLiteral("kdesvnaddrecursive")),
0656                             this,
0657                             SLOT(slotCheckNewItems()));
0658     tmp_action->setIconText(i18n("Unversioned"));
0659     tmp_action->setToolTip(i18n("Browse folder for unversioned items and add them if wanted."));
0660     tmp_action->setStatusTip(tmp_action->toolTip());
0661 
0662     tmp_action = add_action(QStringLiteral("make_switch_to_repo"),
0663                             i18n("Open repository of working copy"),
0664                             QKeySequence(),
0665                             QIcon::fromTheme(QStringLiteral("kdesvnrepository")),
0666                             this,
0667                             SLOT(slotChangeToRepository()));
0668     tmp_action->setToolTip(i18n("Opens the repository the current working copy was checked out from"));
0669 
0670     tmp_action = add_action(QStringLiteral("make_cleanup"),
0671                             i18n("Cleanup"),
0672                             QKeySequence(),
0673                             QIcon::fromTheme(QStringLiteral("kdesvncleanup")),
0674                             this,
0675                             SLOT(slotCleanupAction()));
0676     tmp_action->setToolTip(i18n("Recursively clean up the working copy, removing locks, resuming unfinished operations, etc."));
0677     tmp_action = add_action(QStringLiteral("make_import_dirs_into_current"),
0678                             i18n("Import folders into current"),
0679                             QKeySequence(),
0680                             QIcon::fromTheme(QStringLiteral("kdesvnimportfolder")),
0681                             this,
0682                             SLOT(slotImportDirsIntoCurrent()));
0683     tmp_action->setToolTip(i18n("Import folder content into current URL"));
0684 
0685     /* local only actions */
0686     /* 1. actions on files AND dirs*/
0687     tmp_action = add_action(QStringLiteral("make_svn_add"),
0688                             i18n("Add selected files/dirs"),
0689                             QKeySequence(Qt::Key_Insert),
0690                             QIcon::fromTheme(QStringLiteral("kdesvnadd")),
0691                             m_Data->m_Model->svnWrapper(),
0692                             SLOT(slotAdd()));
0693     tmp_action->setToolTip(i18n("Adding selected files and/or directories to repository"));
0694     tmp_action->setIconText(i18n("Add"));
0695     tmp_action = add_action(QStringLiteral("make_svn_addrec"),
0696                             i18n("Add selected files/dirs recursive"),
0697                             QKeySequence(Qt::CTRL | Qt::Key_Insert),
0698                             QIcon::fromTheme(QStringLiteral("kdesvnaddrecursive")),
0699                             m_Data->m_Model->svnWrapper(),
0700                             SLOT(slotAddRec()));
0701     tmp_action->setToolTip(i18n("Adding selected files and/or directories to repository and all subitems of folders"));
0702 
0703     tmp_action = add_action(QStringLiteral("make_svn_remove"),
0704                             i18n("Delete selected files/dirs"),
0705                             QKeySequence(Qt::Key_Delete),
0706                             QIcon::fromTheme(QStringLiteral("kdesvndelete")),
0707                             this,
0708                             SLOT(slotDelete()));
0709     tmp_action->setIconText(i18n("Delete"));
0710     tmp_action->setToolTip(i18n("Deleting selected files and/or directories from repository"));
0711     tmp_action = add_action(QStringLiteral("make_svn_remove_left"),
0712                             i18n("Delete folder"),
0713                             QKeySequence(),
0714                             QIcon::fromTheme(QStringLiteral("kdesvndelete")),
0715                             this,
0716                             SLOT(slotLeftDelete()));
0717     tmp_action->setToolTip(i18n("Deleting selected directories from repository"));
0718     tmp_action->setIconText(i18n("Delete"));
0719     tmp_action = add_action(QStringLiteral("make_svn_revert"),
0720                             i18n("Revert current changes"),
0721                             QKeySequence(Qt::CTRL | Qt::Key_R),
0722                             QIcon::fromTheme(QStringLiteral("kdesvnreverse")),
0723                             m_Data->m_Model->svnWrapper(),
0724                             SLOT(slotRevert()));
0725 
0726     tmp_action = add_action(QStringLiteral("make_resolved"),
0727                             i18n("Mark resolved"),
0728                             QKeySequence(),
0729                             QIcon::fromTheme(QStringLiteral("kdesvnresolved")),
0730                             this,
0731                             SLOT(slotResolved()));
0732     tmp_action->setToolTip(i18n("Marking files or dirs resolved"));
0733 
0734     tmp_action = add_action(QStringLiteral("make_try_resolve"),
0735                             i18n("Resolve conflicts"),
0736                             QKeySequence(),
0737                             QIcon::fromTheme(QStringLiteral("kdesvnresolved")),
0738                             this,
0739                             SLOT(slotTryResolve()));
0740 
0741     tmp_action = add_action(QStringLiteral("make_svn_ignore"), i18n("Ignore/Unignore current item"), QKeySequence(), QIcon(), this, SLOT(slotIgnore()));
0742     tmp_action = add_action(QStringLiteral("make_left_add_ignore_pattern"),
0743                             i18n("Add or Remove ignore pattern"),
0744                             QKeySequence(),
0745                             QIcon(),
0746                             this,
0747                             SLOT(slotLeftRecAddIgnore()));
0748     tmp_action = add_action(QStringLiteral("make_right_add_ignore_pattern"),
0749                             i18n("Add or Remove ignore pattern"),
0750                             QKeySequence(),
0751                             QIcon(),
0752                             this,
0753                             SLOT(slotRightRecAddIgnore()));
0754 
0755     tmp_action = add_action(QStringLiteral("make_svn_headupdate"),
0756                             i18n("Update to head"),
0757                             QKeySequence(),
0758                             QIcon::fromTheme(QStringLiteral("kdesvnupdate")),
0759                             m_Data->m_Model->svnWrapper(),
0760                             SLOT(slotUpdateHeadRec()));
0761     tmp_action->setIconText(i18nc("Menu item", "Update"));
0762     tmp_action = add_action(QStringLiteral("make_svn_revupdate"),
0763                             i18n("Update to revision..."),
0764                             QKeySequence(),
0765                             QIcon::fromTheme(QStringLiteral("kdesvnupdate")),
0766                             m_Data->m_Model->svnWrapper(),
0767                             SLOT(slotUpdateTo()));
0768     tmp_action = add_action(QStringLiteral("make_svn_commit"),
0769                             i18n("Commit"),
0770                             QKeySequence(QStringLiteral("CTRL+#")),
0771                             QIcon::fromTheme(QStringLiteral("kdesvncommit")),
0772                             this,
0773                             SLOT(slotCommit()));
0774     tmp_action->setIconText(i18n("Commit"));
0775 
0776     tmp_action = add_action(QStringLiteral("make_svn_basediff"),
0777                             i18n("Diff local changes"),
0778                             QKeySequence(Qt::CTRL | Qt::Key_D),
0779                             QIcon::fromTheme(QStringLiteral("kdesvndiff")),
0780                             this,
0781                             SLOT(slotSimpleBaseDiff()));
0782     tmp_action->setToolTip(i18n("Diff working copy against BASE (last checked out version) - does not require access to repository"));
0783     tmp_action = add_action(QStringLiteral("make_svn_dirbasediff"),
0784                             i18n("Diff local changes"),
0785                             QKeySequence(),
0786                             QIcon::fromTheme(QStringLiteral("kdesvndiff")),
0787                             this,
0788                             SLOT(slotDirSimpleBaseDiff()));
0789     tmp_action->setToolTip(i18n("Diff working copy against BASE (last checked out version) - does not require access to repository"));
0790 
0791     tmp_action = add_action(QStringLiteral("make_svn_headdiff"),
0792                             i18n("Diff against HEAD"),
0793                             QKeySequence(Qt::CTRL | Qt::Key_H),
0794                             QIcon::fromTheme(QStringLiteral("kdesvndiff")),
0795                             this,
0796                             SLOT(slotSimpleHeadDiff()));
0797     tmp_action->setToolTip(i18n("Diff working copy against HEAD (last checked in version)- requires access to repository"));
0798 
0799     tmp_action = add_action(QStringLiteral("make_svn_itemsdiff"),
0800                             i18n("Diff items"),
0801                             QKeySequence(),
0802                             QIcon::fromTheme(QStringLiteral("kdesvndiff")),
0803                             this,
0804                             SLOT(slotDiffPathes()));
0805     tmp_action->setToolTip(i18n("Diff two items"));
0806     tmp_action = add_action(QStringLiteral("make_svn_diritemsdiff"),
0807                             i18n("Diff items"),
0808                             QKeySequence(),
0809                             QIcon::fromTheme(QStringLiteral("kdesvndiff")),
0810                             this,
0811                             SLOT(slotDiffPathes()));
0812     tmp_action->setToolTip(i18n("Diff two items"));
0813 
0814     tmp_action = add_action(QStringLiteral("make_svn_merge_revisions"),
0815                             i18n("Merge two revisions"),
0816                             QKeySequence(),
0817                             QIcon::fromTheme(QStringLiteral("kdesvnmerge")),
0818                             this,
0819                             SLOT(slotMergeRevisions()));
0820     tmp_action->setIconText(i18n("Merge"));
0821     tmp_action->setToolTip(i18n("Merge two revisions of this entry into itself"));
0822 
0823     tmp_action = add_action(QStringLiteral("make_svn_merge"),
0824                             i18n("Merge..."),
0825                             QKeySequence(),
0826                             QIcon::fromTheme(QStringLiteral("kdesvnmerge")),
0827                             this,
0828                             SLOT(slotMerge()));
0829     tmp_action->setToolTip(i18n("Merge repository path into current working copy path or current repository path into a target"));
0830     tmp_action = add_action(QStringLiteral("openwith"), i18n("Open With..."), QKeySequence(), QIcon(), this, SLOT(slotOpenWith()));
0831 
0832     /* remote actions only */
0833     tmp_action = add_action(QStringLiteral("make_svn_checkout_current"),
0834                             i18n("Checkout current repository path"),
0835                             QKeySequence(),
0836                             QIcon::fromTheme(QStringLiteral("kdesvncheckout")),
0837                             m_Data->m_Model->svnWrapper(),
0838                             SLOT(slotCheckoutCurrent()));
0839     tmp_action->setIconText(i18n("Checkout"));
0840     tmp_action = add_action(QStringLiteral("make_svn_export_current"),
0841                             i18n("Export current repository path"),
0842                             QKeySequence(),
0843                             QIcon::fromTheme(QStringLiteral("kdesvnexport")),
0844                             m_Data->m_Model->svnWrapper(),
0845                             SLOT(slotExportCurrent()));
0846     add_action(QStringLiteral("switch_browse_revision"), i18n("Select browse revision"), QKeySequence(), QIcon(), this, SLOT(slotSelectBrowsingRevision()));
0847 
0848     /* independe actions */
0849     tmp_action = add_action(QStringLiteral("make_svn_checkout"),
0850                             i18n("Checkout a repository"),
0851                             QKeySequence(),
0852                             QIcon::fromTheme(QStringLiteral("kdesvncheckout")),
0853                             m_Data->m_Model->svnWrapper(),
0854                             SLOT(slotCheckout()));
0855     tmp_action->setIconText(i18n("Checkout"));
0856     tmp_action = add_action(QStringLiteral("make_svn_export"),
0857                             i18n("Export a repository"),
0858                             QKeySequence(),
0859                             QIcon::fromTheme(QStringLiteral("kdesvnexport")),
0860                             m_Data->m_Model->svnWrapper(),
0861                             SLOT(slotExport()));
0862     tmp_action->setIconText(i18n("Export"));
0863     tmp_action = add_action(QStringLiteral("make_view_refresh"),
0864                             i18n("Refresh view"),
0865                             QKeySequence(Qt::Key_F5),
0866                             QIcon::fromTheme(QStringLiteral("kdesvnrightreload")),
0867                             this,
0868                             SLOT(refreshCurrentTree()));
0869     tmp_action->setIconText(i18n("Refresh"));
0870 
0871     add_action(QStringLiteral("make_revisions_diff"),
0872                i18n("Diff revisions"),
0873                QKeySequence(),
0874                QIcon::fromTheme(QStringLiteral("kdesvndiff")),
0875                this,
0876                SLOT(slotDiffRevisions()));
0877 
0878     /* folding options */
0879     tmp_action = add_action(QStringLiteral("view_unfold_tree"), i18n("Unfold File Tree"), QKeySequence(), QIcon(), this, SLOT(slotUnfoldTree()));
0880     tmp_action->setToolTip(i18n("Opens all branches of the file tree"));
0881     tmp_action = add_action(QStringLiteral("view_fold_tree"), i18n("Fold File Tree"), QKeySequence(), QIcon(), this, SLOT(slotFoldTree()));
0882     tmp_action->setToolTip(i18n("Closes all branches of the file tree"));
0883 
0884     /* caching */
0885     tmp_action = add_action(QStringLiteral("update_log_cache"), i18n("Update log cache"), QKeySequence(), QIcon(), this, SLOT(slotUpdateLogCache()));
0886     tmp_action->setToolTip(i18n("Update the log cache for current repository"));
0887 
0888     tmp_action = add_action(QStringLiteral("make_dir_commit"),
0889                             i18n("Commit"),
0890                             QKeySequence(),
0891                             QIcon::fromTheme(QStringLiteral("kdesvncommit")),
0892                             this,
0893                             SLOT(slotDirCommit()));
0894     tmp_action = add_action(QStringLiteral("make_dir_update"),
0895                             i18n("Update to head"),
0896                             QKeySequence(),
0897                             QIcon::fromTheme(QStringLiteral("kdesvnupdate")),
0898                             this,
0899                             SLOT(slotDirUpdate()));
0900     tmp_action = add_action(QStringLiteral("set_rec_property_dir"), i18n("Set property recursive"), QKeySequence(), QIcon(), this, SLOT(slotDirRecProperty()));
0901 
0902     tmp_action = add_action(QStringLiteral("show_repository_settings"),
0903                             i18n("Settings for current repository"),
0904                             QKeySequence(),
0905                             QIcon(),
0906                             this,
0907                             SLOT(slotRepositorySettings()));
0908 
0909     enableActions();
0910 }
0911 
0912 bool MainTreeWidget::uniqueTypeSelected()
0913 {
0914     QModelIndexList _mi = m_TreeView->selectionModel()->selectedRows(0);
0915     if (_mi.count() < 1) {
0916         return false;
0917     }
0918     bool dir = static_cast<SvnItemModelNode *>(m_Data->srcInd(_mi[0]).internalPointer())->isDir();
0919     for (int i = 1; i < _mi.count(); ++i) {
0920         if (static_cast<SvnItemModelNode *>(m_Data->srcInd(_mi[i]).internalPointer())->isDir() != dir) {
0921             return false;
0922         }
0923     }
0924     return true;
0925 }
0926 
0927 void MainTreeWidget::enableAction(const QString &name, bool how)
0928 {
0929     QAction *temp = filesActions()->action(name);
0930     if (temp) {
0931         temp->setEnabled(how);
0932         temp->setVisible(how);
0933     }
0934 }
0935 
0936 void MainTreeWidget::enableActions()
0937 {
0938     const bool isopen = !baseUri().isEmpty();
0939     const SvnItemList fileList = SelectionList();
0940     const SvnItemList dirList = DirSelectionList();
0941     const SvnItemModelNode *si = SelectedNode();
0942 
0943     const bool single = isopen && fileList.size() == 1;
0944     const bool multi = isopen && fileList.size() > 1;
0945     const bool none = isopen && fileList.isEmpty();
0946     const bool single_dir = single && si && si->isDir();
0947     const bool unique = uniqueTypeSelected();
0948     const bool remote_enabled = /*isopen&&*/ m_Data->m_Model->svnWrapper()->doNetworking();
0949     const bool conflicted = single && si && si->isConflicted();
0950 
0951     bool at_least_one_changed = false;
0952     bool at_least_one_conflicted = false;
0953     bool at_least_one_local_added = false;
0954     bool all_unversioned = true;
0955     bool all_versioned = true;
0956     bool at_least_one_directory = false;
0957     for (auto item : fileList) {
0958         if (!item) {
0959             // root item
0960             continue;
0961         }
0962         if (item->isChanged()) {
0963             at_least_one_changed = true;
0964         }
0965         if (item->isConflicted()) {
0966             at_least_one_conflicted = true;
0967         }
0968         if (item->isLocalAdded()) {
0969             at_least_one_local_added = true;
0970         }
0971         if (item->isRealVersioned()) {
0972             all_unversioned = false;
0973         } else {
0974             all_versioned = false;
0975         }
0976         if (item->isDir()) {
0977             at_least_one_directory = true;
0978             if (item->isChildModified())
0979                 at_least_one_changed = true;
0980         }
0981     }
0982 
0983     // qDebug("single: %d, multi: %d, none: %d, single_dir: %d, unique: %d, remove_enabled: %d, conflicted: %d, changed: %d, added: %d",
0984     //        single, multi, none, single_dir, unique, remote_enabled, conflicted, si && si->isChanged(), si && si->isLocalAdded());
0985     // qDebug("at_least_one_changed: %d, at_least_one_conflicted: %d, at_least_one_local_added: %d, all_unversioned: %d, all_versioned: %d,
0986     // at_least_one_directory: %d",
0987     //        at_least_one_changed, at_least_one_conflicted, at_least_one_local_added, all_unversioned, all_versioned, at_least_one_directory);
0988 
0989     /* local and remote actions */
0990     /* 1. actions on dirs AND files */
0991     enableAction(QStringLiteral("make_svn_log_nofollow"), single || none);
0992     enableAction(QStringLiteral("make_svn_dir_log_nofollow"), dirList.size() == 1 && isopen);
0993     enableAction(QStringLiteral("make_last_change"), isopen);
0994     enableAction(QStringLiteral("make_svn_log_full"), single || none);
0995     enableAction(QStringLiteral("make_svn_tree"), single || none);
0996     enableAction(QStringLiteral("make_svn_partialtree"), single || none);
0997 
0998     enableAction(QStringLiteral("make_svn_property"), single);
0999     enableAction(QStringLiteral("make_left_svn_property"), dirList.size() == 1);
1000     enableAction(QStringLiteral("set_rec_property_dir"), dirList.size() == 1);
1001     enableAction(QStringLiteral("get_svn_property"), single);
1002     enableAction(QStringLiteral("make_svn_remove"), (multi || single));
1003     enableAction(QStringLiteral("make_svn_remove_left"), dirList.size() > 0);
1004     enableAction(QStringLiteral("make_svn_lock"), (multi || single));
1005     enableAction(QStringLiteral("make_svn_unlock"), (multi || single));
1006 
1007     enableAction(QStringLiteral("make_svn_ignore"), (single) && si && si->parent() != nullptr && !si->isRealVersioned());
1008     enableAction(QStringLiteral("make_left_add_ignore_pattern"), (dirList.size() == 1) && isWorkingCopy());
1009     enableAction(QStringLiteral("make_right_add_ignore_pattern"), single_dir && isWorkingCopy());
1010 
1011     enableAction(QStringLiteral("make_svn_rename"), single && (!isWorkingCopy() || si != m_Data->m_Model->firstRootChild()));
1012     enableAction(QStringLiteral("make_svn_copy"), single && (!isWorkingCopy() || si != m_Data->m_Model->firstRootChild()));
1013 
1014     /* 2. only on files */
1015     enableAction(QStringLiteral("make_svn_blame"), single && !single_dir && remote_enabled);
1016     enableAction(QStringLiteral("make_svn_range_blame"), single && !single_dir && remote_enabled);
1017     enableAction(QStringLiteral("make_svn_cat"), single && !single_dir);
1018 
1019     /* 3. actions only on dirs */
1020     enableAction(QStringLiteral("make_svn_mkdir"), single_dir || (none && isopen));
1021     enableAction(QStringLiteral("make_svn_switch"), isWorkingCopy() && (single || none));
1022     enableAction(QStringLiteral("make_switch_to_repo"), isWorkingCopy());
1023     enableAction(QStringLiteral("make_import_dirs_into_current"), single_dir || dirList.size() == 1);
1024     enableAction(QStringLiteral("make_svn_relocate"), isWorkingCopy() && (single || none));
1025 
1026     enableAction(QStringLiteral("make_svn_export_current"), ((single && single_dir) || none));
1027 
1028     /* local only actions */
1029     /* 1. actions on files AND dirs*/
1030     enableAction(QStringLiteral("make_svn_add"), (multi || single) && isWorkingCopy() && all_unversioned);
1031     enableAction(QStringLiteral("make_svn_revert"),
1032                  (multi || single) && isWorkingCopy() && (at_least_one_changed || at_least_one_conflicted || at_least_one_local_added));
1033     enableAction(QStringLiteral("make_resolved"), (multi || single) && isWorkingCopy());
1034     enableAction(QStringLiteral("make_try_resolve"), conflicted && !single_dir);
1035 
1036     enableAction(QStringLiteral("make_svn_info"), isopen);
1037     enableAction(QStringLiteral("make_svn_merge_revisions"), (single || dirList.size() == 1) && isWorkingCopy());
1038     enableAction(QStringLiteral("make_svn_merge"), single || dirList.size() == 1 || none);
1039     enableAction(QStringLiteral("make_svn_addrec"), (multi || single) && at_least_one_directory && isWorkingCopy() && all_unversioned);
1040     enableAction(QStringLiteral("make_svn_headupdate"), isWorkingCopy() && isopen && remote_enabled);
1041     enableAction(QStringLiteral("make_dir_update"), isWorkingCopy() && isopen && remote_enabled);
1042 
1043     enableAction(QStringLiteral("make_svn_revupdate"), isWorkingCopy() && isopen && remote_enabled);
1044     enableAction(QStringLiteral("make_svn_commit"), isWorkingCopy() && isopen && remote_enabled);
1045     enableAction(QStringLiteral("make_dir_commit"), isWorkingCopy() && isopen && remote_enabled);
1046 
1047     enableAction(QStringLiteral("make_svn_basediff"), isWorkingCopy() && (single || none));
1048     enableAction(QStringLiteral("make_svn_dirbasediff"), isWorkingCopy() && (dirList.size() < 2));
1049     enableAction(QStringLiteral("make_svn_headdiff"), isWorkingCopy() && (single || none) && remote_enabled);
1050 
1051     /// @todo check if all items have same type
1052     enableAction(QStringLiteral("make_svn_itemsdiff"), multi && fileList.size() == 2 && unique && remote_enabled && all_versioned);
1053     enableAction(QStringLiteral("make_svn_diritemsdiff"), dirList.size() == 2 && isopen && remote_enabled && all_versioned);
1054 
1055     /* 2. on dirs only */
1056     enableAction(QStringLiteral("make_cleanup"), isWorkingCopy() && (single_dir || none));
1057     enableAction(QStringLiteral("make_check_unversioned"), isWorkingCopy() && ((single_dir && single) || none));
1058 
1059     /* remote actions only */
1060     enableAction(QStringLiteral("make_svn_checkout_current"), ((single && single_dir) || none) && !isWorkingCopy() && remote_enabled);
1061     /* independ actions */
1062     enableAction(QStringLiteral("make_svn_checkout"), remote_enabled);
1063     enableAction(QStringLiteral("make_svn_export"), true);
1064     enableAction(QStringLiteral("make_view_refresh"), isopen);
1065 
1066     enableAction(QStringLiteral("make_revisions_diff"), isopen);
1067     enableAction(QStringLiteral("make_revisions_cat"), isopen && !single_dir && single);
1068     enableAction(QStringLiteral("switch_browse_revision"), !isWorkingCopy() && isopen);
1069     enableAction(QStringLiteral("make_check_updates"), isWorkingCopy() && isopen && remote_enabled);
1070     enableAction(QStringLiteral("openwith"), KAuthorized::authorizeAction("openwith") && single && !single_dir);
1071     enableAction(QStringLiteral("show_repository_settings"), isopen);
1072 
1073     enableAction(QStringLiteral("repo_statistic"), isopen);
1074 
1075     QAction *temp = filesActions()->action(QStringLiteral("update_log_cache"));
1076     if (temp) {
1077         temp->setEnabled(remote_enabled);
1078         if (!m_Data->m_Model->svnWrapper()->threadRunning(SvnActions::fillcachethread)) {
1079             temp->setText(i18n("Update log cache"));
1080         } else {
1081             temp->setText(i18n("Stop updating the log cache"));
1082         }
1083     }
1084 }
1085 
1086 QAction *
1087 MainTreeWidget::add_action(const QString &actionname, const QString &text, const QKeySequence &sequ, const QIcon &icon, QObject *target, const char *slot)
1088 {
1089     QAction *tmp_action = nullptr;
1090     tmp_action = m_Data->m_Collection->addAction(actionname, target, slot);
1091     tmp_action->setText(text);
1092     m_Data->m_Collection->setDefaultShortcut(tmp_action, sequ);
1093     tmp_action->setIcon(icon);
1094     return tmp_action;
1095 }
1096 
1097 KActionCollection *MainTreeWidget::filesActions()
1098 {
1099     return m_Data->m_Collection;
1100 }
1101 
1102 void MainTreeWidget::closeMe()
1103 {
1104     m_Data->m_Model->svnWrapper()->killallThreads();
1105 
1106     clear();
1107     setWorkingCopy(true);
1108     setNetworked(false);
1109     setWorkingCopy(false);
1110     setBaseUri(QString());
1111 
1112     emit changeCaption(QString());
1113     emit sigUrlOpened(false);
1114     emit sigUrlChanged(QUrl());
1115 
1116     enableActions();
1117     m_Data->m_Model->svnWrapper()->reInitClient();
1118 }
1119 
1120 void MainTreeWidget::refreshCurrentTree()
1121 {
1122     m_Data->m_Model->refreshCurrentTree();
1123     if (isWorkingCopy()) {
1124         m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
1125     }
1126     m_Data->m_SortModel->invalidate();
1127     setUpdatesEnabled(true);
1128     // viewport()->repaint();
1129     QTimer::singleShot(1, this, &MainTreeWidget::readSupportData);
1130 }
1131 
1132 void MainTreeWidget::slotSettingsChanged()
1133 {
1134     m_Data->m_SortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
1135     m_Data->m_SortModel->invalidate();
1136     m_Data->m_DirSortModel->invalidate();
1137     enableActions();
1138     if (m_Data->m_Model->svnWrapper() && !m_Data->m_Model->svnWrapper()->doNetworking()) {
1139         m_Data->m_Model->svnWrapper()->stopFillCache();
1140     }
1141     checkUseNavigation();
1142 }
1143 
1144 KService::List MainTreeWidget::offersList(SvnItem *item, bool execOnly) const
1145 {
1146     KService::List offers;
1147     if (!item) {
1148         return offers;
1149     }
1150     if (!item->mimeType().isValid()) {
1151         return offers;
1152     }
1153 
1154     offers = KApplicationTrader::queryByMimeType(item->mimeType().name(), [](const KService::Ptr service) {
1155         return service->desktopEntryName() != QLatin1String("org.kde.kdesvn");
1156     });
1157 
1158     return offers;
1159 }
1160 
1161 void MainTreeWidget::slotItemActivated(const QModelIndex &_index)
1162 {
1163     QModelIndex index = m_Data->m_SortModel->mapToSource(_index);
1164     itemActivated(index);
1165 }
1166 
1167 void MainTreeWidget::itemActivated(const QModelIndex &index, bool keypress)
1168 {
1169     Q_UNUSED(keypress);
1170     SvnItemModelNode *item;
1171     if (index.isValid() && (item = static_cast<SvnItemModelNode *>(index.internalPointer()))) {
1172         if (!item->isDir()) {
1173             svn::Revision rev;
1174             QList<QUrl> lst;
1175             lst.append(item->kdeName(rev));
1176             KService::List li = offersList(item, true);
1177             if (li.isEmpty() || li.first()->exec().isEmpty()) {
1178                 li = offersList(item);
1179             }
1180             if (!li.isEmpty() && !li.first()->exec().isEmpty()) {
1181                 KService::Ptr ptr = li.first();
1182                 auto *job = new KIO::ApplicationLauncherJob(ptr);
1183                 job->setUrls(lst);
1184                 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled, QApplication::activeWindow()));
1185                 job->start();
1186             } else {
1187                 auto *job = new KIO::ApplicationLauncherJob;
1188                 job->setUrls(lst);
1189                 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled, QApplication::activeWindow()));
1190                 job->start();
1191             }
1192         } else if (Kdesvnsettings::show_navigation_panel()) {
1193             m_DirTreeView->selectionModel()->select(m_Data->m_DirSortModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect);
1194             QModelIndex _ind = m_Data->m_Model->parent(index);
1195             if (_ind.isValid()) {
1196                 m_DirTreeView->expand(m_Data->m_DirSortModel->mapFromSource(_ind));
1197             }
1198         } else {
1199         }
1200     }
1201 }
1202 
1203 void MainTreeWidget::slotCheckUpdates()
1204 {
1205     if (isWorkingCopy() && m_Data->m_Model->svnWrapper()->doNetworking()) {
1206         m_Data->m_TimeUpdates.stop();
1207         m_Data->m_Model->svnWrapper()->createUpdateCache(baseUri());
1208     }
1209 }
1210 
1211 void MainTreeWidget::slotCheckModified()
1212 {
1213     if (isWorkingCopy()) {
1214         m_Data->m_TimeModified.stop();
1215         m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
1216     }
1217 }
1218 
1219 void MainTreeWidget::slotNotifyMessage(const QString &what)
1220 {
1221     emit sigLogMessage(what);
1222     QCoreApplication::processEvents();
1223 }
1224 
1225 void MainTreeWidget::readSupportData()
1226 {
1227     /// this moment empty cause no usagedata explicit used by MainTreeWidget
1228 }
1229 
1230 void MainTreeWidget::slotClientException(const QString &what)
1231 {
1232     emit sigLogMessage(what);
1233     KMessageBox::error(QApplication::activeModalWidget(), what, i18n("SVN Error"));
1234 }
1235 
1236 void MainTreeWidget::slotCacheDataChanged()
1237 {
1238     m_Data->m_SortModel->invalidate();
1239     if (isWorkingCopy()) {
1240         if (!m_Data->m_TimeModified.isActive() && Kdesvnsettings::poll_modified()) {
1241             m_Data->m_TimeModified.setInterval(MinutesToMsec(Kdesvnsettings::poll_modified_minutes()));
1242             m_Data->m_TimeModified.start();
1243         }
1244         if (!m_Data->m_TimeUpdates.isActive() && Kdesvnsettings::poll_updates()) {
1245             m_Data->m_TimeUpdates.setInterval(MinutesToMsec(Kdesvnsettings::poll_updates_minutes()));
1246             m_Data->m_TimeUpdates.start();
1247         }
1248     }
1249 }
1250 
1251 void MainTreeWidget::slotIgnore()
1252 {
1253     m_Data->m_Model->makeIgnore(SelectedIndex());
1254     m_Data->m_SortModel->invalidate();
1255 }
1256 
1257 void MainTreeWidget::slotLeftRecAddIgnore()
1258 {
1259     SvnItem *item = DirSelected();
1260     if (!item || !item->isDir()) {
1261         return;
1262     }
1263     recAddIgnore(item);
1264 }
1265 
1266 void MainTreeWidget::slotRightRecAddIgnore()
1267 {
1268     SvnItem *item = Selected();
1269     if (!item || !item->isDir()) {
1270         return;
1271     }
1272     recAddIgnore(item);
1273 }
1274 
1275 void MainTreeWidget::recAddIgnore(SvnItem *item)
1276 {
1277     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("ignore_pattern_dlg")));
1278     dlg->setWindowTitle(i18nc("@title:window", "Edit Pattern to Ignore for \"%1\"", item->shortName()));
1279     dlg->setWithCancelButton();
1280     EditIgnorePattern *ptr(new EditIgnorePattern(dlg));
1281     dlg->addWidget(ptr);
1282     if (dlg->exec() != QDialog::Accepted) {
1283         delete dlg;
1284         return;
1285     }
1286     svn::Depth _d = ptr->depth();
1287     QStringList _pattern = ptr->items();
1288     bool unignore = ptr->unignore();
1289     svn::Revision start(svn::Revision::WORKING);
1290     if (!isWorkingCopy()) {
1291         start = baseRevision();
1292     }
1293 
1294     svn::StatusEntries res;
1295     if (!m_Data->m_Model->svnWrapper()->makeStatus(item->fullName(), res, start, _d, true /* all entries */, false, false)) {
1296         return;
1297     }
1298     for (const svn::StatusPtr &ptr : qAsConst(res)) {
1299         if (!ptr->isRealVersioned() || ptr->entry().kind() != svn_node_dir) {
1300             continue;
1301         }
1302         m_Data->m_Model->svnWrapper()->makeIgnoreEntry(ptr->path(), _pattern, unignore);
1303     }
1304     refreshCurrentTree();
1305     delete dlg;
1306 }
1307 
1308 void MainTreeWidget::slotMakeLogNoFollow() const
1309 {
1310     doLog(false, false);
1311 }
1312 
1313 void MainTreeWidget::slotMakeLog() const
1314 {
1315     doLog(true, false);
1316 }
1317 
1318 void MainTreeWidget::slotDirMakeLogNoFollow() const
1319 {
1320     doLog(false, true);
1321 }
1322 
1323 void MainTreeWidget::doLog(bool use_follow_settings, bool left) const
1324 {
1325     SvnItem *k = left ? DirSelectedOrMain() : SelectedOrMain();
1326     QString what;
1327     if (k) {
1328         what = k->fullName();
1329     } else if (!isWorkingCopy() && selectionCount() == 0) {
1330         what = baseUri();
1331     } else {
1332         return;
1333     }
1334     svn::Revision start(svn::Revision::HEAD);
1335     if (!isWorkingCopy()) {
1336         start = baseRevision();
1337     }
1338     svn::Revision end(svn::Revision::START);
1339     bool list = Kdesvnsettings::self()->log_always_list_changed_files();
1340     bool follow = use_follow_settings ? Kdesvnsettings::log_follows_nodes() : false;
1341     Kdesvnsettings::setLast_node_follow(follow);
1342     int l = 50;
1343     m_Data->m_Model->svnWrapper()->makeLog(start, end, (isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision()), what, follow, list, l);
1344 }
1345 
1346 void MainTreeWidget::slotContextMenu(const QPoint &)
1347 {
1348     execContextMenu(SelectionList());
1349 }
1350 
1351 void MainTreeWidget::slotDirContextMenu(const QPoint &vp)
1352 {
1353     QMenu popup;
1354     QAction *temp = nullptr;
1355     int count = 0;
1356     if ((temp = filesActions()->action(QStringLiteral("make_dir_commit"))) && temp->isEnabled() && ++count) {
1357         popup.addAction(temp);
1358     }
1359     if ((temp = filesActions()->action(QStringLiteral("make_dir_update"))) && temp->isEnabled() && ++count) {
1360         popup.addAction(temp);
1361     }
1362     if ((temp = filesActions()->action(QStringLiteral("make_svn_dirbasediff"))) && temp->isEnabled() && ++count) {
1363         popup.addAction(temp);
1364     }
1365     if ((temp = filesActions()->action(QStringLiteral("make_svn_diritemsdiff"))) && temp->isEnabled() && ++count) {
1366         popup.addAction(temp);
1367     }
1368     if ((temp = filesActions()->action(QStringLiteral("make_svn_dir_log_nofollow"))) && temp->isEnabled() && ++count) {
1369         popup.addAction(temp);
1370     }
1371     if ((temp = filesActions()->action(QStringLiteral("make_left_svn_property"))) && temp->isEnabled() && ++count) {
1372         popup.addAction(temp);
1373     }
1374     if ((temp = filesActions()->action(QStringLiteral("make_svn_remove_left"))) && temp->isEnabled() && ++count) {
1375         popup.addAction(temp);
1376     }
1377     if ((temp = filesActions()->action(QStringLiteral("make_left_add_ignore_pattern"))) && temp->isEnabled() && ++count) {
1378         popup.addAction(temp);
1379     }
1380     if ((temp = filesActions()->action(QStringLiteral("set_rec_property_dir"))) && temp->isEnabled() && ++count) {
1381         popup.addAction(temp);
1382     }
1383 
1384     OpenContextmenu *me = nullptr;
1385     QAction *menuAction = nullptr;
1386     const SvnItemList l = DirSelectionList();
1387     if (l.count() == 1 && l.at(0)) {
1388         const KService::List offers = offersList(l.at(0), l.at(0)->isDir());
1389         if (!offers.isEmpty()) {
1390             svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1391             me = new OpenContextmenu(l.at(0)->kdeName(rev), offers, nullptr);
1392             me->setTitle(i18n("Open With..."));
1393             menuAction = popup.addMenu(me);
1394             ++count;
1395         }
1396     }
1397     if (count) {
1398         popup.exec(m_DirTreeView->viewport()->mapToGlobal(vp));
1399     }
1400     if (menuAction) {
1401         popup.removeAction(menuAction);
1402         delete menuAction;
1403     }
1404     delete me;
1405 }
1406 
1407 void MainTreeWidget::execContextMenu(const SvnItemList &l)
1408 {
1409     bool isopen = baseUri().length() > 0;
1410     QString menuname;
1411 
1412     if (!isopen) {
1413         menuname = "empty";
1414     } else if (isWorkingCopy()) {
1415         menuname = "local";
1416     } else {
1417         menuname = "remote";
1418     }
1419     if (l.isEmpty()) {
1420         menuname += "_general";
1421     } else if (l.count() > 1) {
1422         menuname += "_context_multi";
1423     } else {
1424         menuname += "_context_single";
1425         if (isWorkingCopy()) {
1426             if (l.at(0)->isRealVersioned()) {
1427                 if (l.at(0)->isConflicted()) {
1428                     menuname += "_conflicted";
1429                 } else {
1430                     menuname += "_versioned";
1431                     if (l.at(0)->isDir()) {
1432                         menuname += "_dir";
1433                     }
1434                 }
1435             } else {
1436                 menuname += "_unversioned";
1437             }
1438         } else if (l.at(0)->isDir()) {
1439             menuname += "_dir";
1440         }
1441     }
1442 
1443     // qDebug("menuname: %s", qPrintable(menuname));
1444     QWidget *target;
1445     emit sigShowPopup(menuname, &target);
1446     QMenu *popup = static_cast<QMenu *>(target);
1447     if (!popup) {
1448         return;
1449     }
1450 
1451     OpenContextmenu *me = nullptr;
1452     QAction *temp = nullptr;
1453     QAction *menuAction = nullptr;
1454     if (l.count() == 1 /*&&!l.at(0)->isDir()*/) {
1455         KService::List offers = offersList(l.at(0), l.at(0)->isDir());
1456         if (!offers.isEmpty()) {
1457             svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1458             me = new OpenContextmenu(l.at(0)->kdeName(rev), offers, nullptr);
1459             me->setTitle(i18n("Open With..."));
1460             menuAction = popup->addMenu(me);
1461         } else {
1462             temp = filesActions()->action(QStringLiteral("openwith"));
1463             if (temp) {
1464                 popup->addAction(temp);
1465             }
1466         }
1467     }
1468     popup->exec(QCursor::pos());
1469     if (menuAction) {
1470         popup->removeAction(menuAction);
1471     }
1472     delete me;
1473     if (temp) {
1474         popup->removeAction(temp);
1475         delete temp;
1476     }
1477 }
1478 
1479 void MainTreeWidget::slotUnfoldTree()
1480 {
1481     m_TreeView->expandAll();
1482 }
1483 
1484 void MainTreeWidget::slotFoldTree()
1485 {
1486     m_TreeView->collapseAll();
1487 }
1488 
1489 void MainTreeWidget::slotOpenWith()
1490 {
1491     SvnItem *which = Selected();
1492     if (!which || which->isDir()) {
1493         return;
1494     }
1495     svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1496     QList<QUrl> lst;
1497     lst.append(which->kdeName(rev));
1498     auto *job = new KIO::ApplicationLauncherJob;
1499     job->setUrls(lst);
1500     job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled, QApplication::activeWindow()));
1501     job->start();
1502 }
1503 
1504 void MainTreeWidget::slotSelectBrowsingRevision()
1505 {
1506     if (isWorkingCopy()) {
1507         return;
1508     }
1509     Rangeinput_impl::revision_range range;
1510     if (Rangeinput_impl::getRevisionRange(range, false)) {
1511         m_Data->m_remoteRevision = range.first;
1512         clear();
1513         m_Data->m_Model->checkDirs(baseUri(), nullptr);
1514         emit changeCaption(baseUri() + QLatin1Char('@') + range.first.toString());
1515     }
1516 }
1517 
1518 void MainTreeWidget::slotMakeTree()
1519 {
1520     QString what;
1521     SvnItem *k = SelectedOrMain();
1522     if (k) {
1523         what = k->fullName();
1524     } else if (!isWorkingCopy() && selectionCount() == 0) {
1525         what = baseUri();
1526     } else {
1527         return;
1528     }
1529     svn::Revision rev(isWorkingCopy() ? svn::Revision::WORKING : baseRevision());
1530 
1531     m_Data->m_Model->svnWrapper()->makeTree(what, rev);
1532 }
1533 
1534 void MainTreeWidget::slotMakePartTree()
1535 {
1536     QString what;
1537     SvnItem *k = SelectedOrMain();
1538     if (k) {
1539         what = k->fullName();
1540     } else if (!isWorkingCopy() && selectionCount() == 0) {
1541         what = baseUri();
1542     } else {
1543         return;
1544     }
1545     Rangeinput_impl::revision_range range;
1546     if (Rangeinput_impl::getRevisionRange(range)) {
1547         svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1548         m_Data->m_Model->svnWrapper()->makeTree(what, rev, range.first, range.second);
1549     }
1550 }
1551 
1552 void MainTreeWidget::slotLock()
1553 {
1554     const SvnItemList lst = SelectionList();
1555     if (lst.isEmpty()) {
1556         KMessageBox::error(this, i18n("Nothing selected for unlock"));
1557         return;
1558     }
1559     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("locking_log_msg")));
1560     dlg->setWindowTitle(i18nc("@title:window", "Lock Message"));
1561     dlg->setWithCancelButton();
1562     Commitmsg_impl *ptr(new Commitmsg_impl(dlg));
1563     ptr->initHistory();
1564     ptr->hideDepth(true);
1565     ptr->keepsLocks(false);
1566 
1567     QCheckBox *_stealLock = new QCheckBox(i18n("Steal lock?"));
1568     ptr->addItemWidget(_stealLock);
1569 
1570     dlg->addWidget(ptr);
1571     if (dlg->exec() != QDialog::Accepted) {
1572         if (dlg)
1573             ptr->saveHistory(true);
1574         delete dlg;
1575         return;
1576     }
1577 
1578     QString logMessage = ptr->getMessage();
1579     bool steal = _stealLock->isChecked();
1580     ptr->saveHistory(false);
1581 
1582     QStringList displist;
1583     for (const SvnItem *item : lst) {
1584         displist.append(item->fullName());
1585     }
1586     m_Data->m_Model->svnWrapper()->makeLock(displist, logMessage, steal);
1587     refreshCurrentTree();
1588 
1589     delete dlg;
1590 }
1591 
1592 /*!
1593     \fn MainTreeWidget::slotUnlock()
1594  */
1595 void MainTreeWidget::slotUnlock()
1596 {
1597     const SvnItemList lst = SelectionList();
1598     if (lst.isEmpty()) {
1599         KMessageBox::error(this, i18n("Nothing selected for unlock"));
1600         return;
1601     }
1602     KMessageBox::ButtonCode res = KMessageBox::questionTwoActionsCancel(this,
1603                                                                         i18n("Break lock or ignore missing locks?"),
1604                                                                         i18n("Unlocking items"),
1605                                                                         KGuiItem(i18nc("@action:button", "Break Lock")),
1606                                                                         KGuiItem(i18nc("@action:button", "Ignore")));
1607     if (res == KMessageBox::Cancel) {
1608         return;
1609     }
1610     const bool breakit = (res == KMessageBox::PrimaryAction);
1611 
1612     QStringList displist;
1613     for (const SvnItem *item : lst) {
1614         displist.append(item->fullName());
1615     }
1616     m_Data->m_Model->svnWrapper()->makeUnlock(displist, breakit);
1617     refreshCurrentTree();
1618 }
1619 
1620 void MainTreeWidget::slotDisplayLastDiff()
1621 {
1622     SvnItem *kitem = Selected();
1623     QString what;
1624     if (isWorkingCopy()) {
1625         QDir::setCurrent(baseUri());
1626     }
1627     svn::Revision end = svn::Revision::PREV;
1628     if (!kitem) {
1629         if (isWorkingCopy()) {
1630             kitem = m_Data->m_Model->firstRootChild();
1631             if (!kitem) {
1632                 return;
1633             }
1634             what = relativePath(kitem);
1635         } else {
1636             what = baseUri();
1637         }
1638     } else {
1639         what = relativePath(kitem);
1640     }
1641     svn::Revision start;
1642     svn::InfoEntry inf;
1643     if (!kitem) {
1644         // it has to have an item when in working copy, so we know we are in repository view.
1645         if (!m_Data->m_Model->svnWrapper()->singleInfo(what, baseRevision(), inf)) {
1646             return;
1647         }
1648         start = inf.cmtRev();
1649     } else {
1650         start = kitem->cmtRev();
1651     }
1652     if (!isWorkingCopy()) {
1653         if (!m_Data->m_Model->svnWrapper()->singleInfo(what, start.revnum() - 1, inf)) {
1654             return;
1655         }
1656         end = inf.cmtRev();
1657     }
1658     m_Data->m_Model->svnWrapper()->makeDiff(what, end, what, start, realWidget());
1659 }
1660 
1661 void MainTreeWidget::slotSimpleBaseDiff()
1662 {
1663     simpleWcDiff(Selected(), svn::Revision::BASE, svn::Revision::WORKING);
1664 }
1665 
1666 void MainTreeWidget::slotDirSimpleBaseDiff()
1667 {
1668     simpleWcDiff(DirSelected(), svn::Revision::BASE, svn::Revision::WORKING);
1669 }
1670 
1671 void MainTreeWidget::slotSimpleHeadDiff()
1672 {
1673     simpleWcDiff(Selected(), svn::Revision::WORKING, svn::Revision::HEAD);
1674 }
1675 
1676 void MainTreeWidget::simpleWcDiff(SvnItem *kitem, const svn::Revision &first, const svn::Revision &second)
1677 {
1678     QString what;
1679     if (isWorkingCopy()) {
1680         QDir::setCurrent(baseUri());
1681     }
1682 
1683     if (!kitem) {
1684         what = QLatin1Char('.');
1685     } else {
1686         what = relativePath(kitem);
1687     }
1688     // only possible on working copies - so we may say this values
1689     m_Data->m_Model->svnWrapper()->makeDiff(what, first, second, svn::Revision::UNDEFINED, kitem ? kitem->isDir() : true);
1690 }
1691 
1692 void MainTreeWidget::slotDiffRevisions()
1693 {
1694     SvnItem *k = Selected();
1695     QString what;
1696     if (isWorkingCopy()) {
1697         QDir::setCurrent(baseUri());
1698     }
1699 
1700     if (!k) {
1701         what = (isWorkingCopy() ? "." : baseUri());
1702     } else {
1703         what = relativePath(k);
1704     }
1705     Rangeinput_impl::revision_range range;
1706     if (Rangeinput_impl::getRevisionRange(range)) {
1707         svn::Revision _peg = (isWorkingCopy() ? svn::Revision::WORKING : baseRevision());
1708         m_Data->m_Model->svnWrapper()->makeDiff(what, range.first, range.second, _peg, k ? k->isDir() : true);
1709     }
1710 }
1711 
1712 void MainTreeWidget::slotDiffPathes()
1713 {
1714     SvnItemList lst;
1715 
1716     QObject *tr = sender();
1717     bool unique = false;
1718 
1719     if (tr == filesActions()->action(QStringLiteral("make_svn_diritemsdiff"))) {
1720         unique = true;
1721         lst = DirSelectionList();
1722     } else {
1723         lst = SelectionList();
1724     }
1725 
1726     if (lst.count() != 2 || (!unique && !uniqueTypeSelected())) {
1727         return;
1728     }
1729 
1730     SvnItem *k1 = lst.at(0);
1731     SvnItem *k2 = lst.at(1);
1732     QString w1, w2;
1733     svn::Revision r1;
1734 
1735     if (isWorkingCopy()) {
1736         QDir::setCurrent(baseUri());
1737         w1 = relativePath(k1);
1738         w2 = relativePath(k2);
1739         r1 = svn::Revision::WORKING;
1740     } else {
1741         w1 = k1->fullName();
1742         w2 = k2->fullName();
1743         r1 = baseRevision();
1744     }
1745     m_Data->m_Model->svnWrapper()->makeDiff(w1, r1, w2, r1);
1746 }
1747 
1748 void MainTreeWidget::slotInfo()
1749 {
1750     svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1751     if (!isWorkingCopy()) {
1752         rev = baseRevision();
1753     }
1754     SvnItemList lst = SelectionList();
1755     if (lst.isEmpty()) {
1756         if (!isWorkingCopy()) {
1757             QStringList _sl(baseUri());
1758             m_Data->m_Model->svnWrapper()->makeInfo(_sl, rev, svn::Revision::UNDEFINED, Kdesvnsettings::info_recursive());
1759         } else {
1760             lst.append(SelectedOrMain());
1761         }
1762     }
1763     if (!lst.isEmpty()) {
1764         m_Data->m_Model->svnWrapper()->makeInfo(lst, rev, rev, Kdesvnsettings::info_recursive());
1765     }
1766 }
1767 
1768 void MainTreeWidget::slotBlame()
1769 {
1770     SvnItem *k = Selected();
1771     if (!k) {
1772         return;
1773     }
1774     svn::Revision start(svn::Revision::START);
1775     svn::Revision end(svn::Revision::HEAD);
1776     m_Data->m_Model->svnWrapper()->makeBlame(start, end, k);
1777 }
1778 
1779 void MainTreeWidget::slotRangeBlame()
1780 {
1781     SvnItem *k = Selected();
1782     if (!k) {
1783         return;
1784     }
1785     Rangeinput_impl::revision_range range;
1786     if (Rangeinput_impl::getRevisionRange(range)) {
1787         m_Data->m_Model->svnWrapper()->makeBlame(range.first, range.second, k);
1788     }
1789 }
1790 
1791 void MainTreeWidget::_propListTimeout()
1792 {
1793     dispProperties(false);
1794 }
1795 
1796 void MainTreeWidget::slotDisplayProperties()
1797 {
1798     dispProperties(true);
1799 }
1800 
1801 void MainTreeWidget::refreshItem(SvnItemModelNode *node)
1802 {
1803     if (node) {
1804         m_Data->m_Model->refreshItem(node);
1805     }
1806 }
1807 
1808 void MainTreeWidget::slotChangeProperties(const svn::PropertiesMap &pm, const QStringList &dellist, const QString &path)
1809 {
1810     m_Data->m_Model->svnWrapper()->changeProperties(pm, dellist, path);
1811     SvnItemModelNode *which = SelectedNode();
1812     if (which && which->fullName() == path) {
1813         m_Data->m_Model->refreshItem(which);
1814         dispProperties(true);
1815     }
1816 }
1817 
1818 void MainTreeWidget::dispProperties(bool force)
1819 {
1820     CursorStack a(Qt::BusyCursor);
1821     bool cache_Only = (!force && isNetworked() && !Kdesvnsettings::properties_on_remote_items());
1822     svn::PathPropertiesMapListPtr pm;
1823     SvnItem *k = Selected();
1824     if (!k || !k->isRealVersioned()) {
1825         emit sigProplist(svn::PathPropertiesMapListPtr(), false, false, QString(""));
1826         return;
1827     }
1828     svn::Revision rev(isWorkingCopy() ? svn::Revision::WORKING : baseRevision());
1829     pm = m_Data->m_Model->svnWrapper()->propList(k->fullName(), rev, cache_Only);
1830     emit sigProplist(pm, isWorkingCopy(), k->isDir(), k->fullName());
1831 }
1832 
1833 void MainTreeWidget::slotCat()
1834 {
1835     SvnItem *k = Selected();
1836     if (!k) {
1837         return;
1838     }
1839     m_Data->m_Model->svnWrapper()->slotMakeCat(isWorkingCopy() ? svn::Revision::HEAD : baseRevision(),
1840                                                k->fullName(),
1841                                                k->shortName(),
1842                                                isWorkingCopy() ? svn::Revision::HEAD : baseRevision(),
1843                                                nullptr);
1844 }
1845 
1846 void MainTreeWidget::slotRevisionCat()
1847 {
1848     SvnItem *k = Selected();
1849     if (!k) {
1850         return;
1851     }
1852     Rangeinput_impl::revision_range range;
1853     if (Rangeinput_impl::getRevisionRange(range, true, true)) {
1854         m_Data->m_Model->svnWrapper()->slotMakeCat(range.first,
1855                                                    k->fullName(),
1856                                                    k->shortName(),
1857                                                    isWorkingCopy() ? svn::Revision::WORKING : baseRevision(),
1858                                                    nullptr);
1859     }
1860 }
1861 
1862 void MainTreeWidget::slotResolved()
1863 {
1864     if (!isWorkingCopy()) {
1865         return;
1866     }
1867     SvnItem *which = SelectedOrMain();
1868     if (!which) {
1869         return;
1870     }
1871     m_Data->m_Model->svnWrapper()->slotResolved(which->fullName());
1872     which->refreshStatus(true);
1873 }
1874 
1875 void MainTreeWidget::slotTryResolve()
1876 {
1877     if (!isWorkingCopy()) {
1878         return;
1879     }
1880     SvnItem *which = Selected();
1881     if (!which || which->isDir()) {
1882         return;
1883     }
1884     m_Data->m_Model->svnWrapper()->slotResolve(which->fullName());
1885 }
1886 
1887 void MainTreeWidget::slotLeftDelete()
1888 {
1889     makeDelete(DirSelectionList());
1890 }
1891 
1892 void MainTreeWidget::slotDelete()
1893 {
1894     makeDelete(SelectionList());
1895 }
1896 
1897 void MainTreeWidget::makeDelete(const SvnItemList &lst)
1898 {
1899     if (lst.isEmpty()) {
1900         KMessageBox::error(this, i18n("Nothing selected for delete"));
1901         return;
1902     }
1903     svn::Paths items;
1904     QStringList displist;
1905     QList<QUrl> kioList;
1906     for (const SvnItem *item : lst) {
1907         if (!item->isRealVersioned()) {
1908             QUrl _uri(QUrl::fromLocalFile(item->fullName()));
1909             kioList.append(_uri);
1910         } else {
1911             items.push_back(item->fullName());
1912         }
1913         displist.append(item->fullName());
1914     }
1915 
1916     QPointer<DeleteForm> dlg(new DeleteForm(displist, QApplication::activeModalWidget()));
1917     dlg->showExtraButtons(isWorkingCopy() && !items.isEmpty());
1918 
1919     if (dlg->exec() == QDialog::Accepted) {
1920         bool force = dlg->force_delete();
1921         bool keep = dlg->keep_local();
1922         WidgetBlockStack st(this);
1923         if (!kioList.isEmpty()) {
1924             KIO::Job *aJob = KIO::del(kioList);
1925             if (!aJob->exec()) {
1926                 KJobWidgets::setWindow(aJob, this);
1927                 aJob->uiDelegate()->showErrorMessage();
1928                 delete dlg;
1929                 return;
1930             }
1931         }
1932         if (!items.isEmpty()) {
1933             m_Data->m_Model->svnWrapper()->makeDelete(svn::Targets(items), keep, force);
1934         }
1935         refreshCurrentTree();
1936     }
1937     delete dlg;
1938 }
1939 
1940 void MainTreeWidget::internalDrop(const QList<QUrl> &_lst, Qt::DropAction action, const QModelIndex &index)
1941 {
1942     if (_lst.isEmpty()) {
1943         return;
1944     }
1945     QList<QUrl> lst = _lst;
1946     QString target;
1947     QString nProto;
1948 
1949     if (!isWorkingCopy()) {
1950         nProto = svn::Url::transformProtokoll(lst[0].scheme());
1951     }
1952     for (QUrl &url : lst) {
1953         url.setQuery(QUrlQuery());
1954         if (!nProto.isEmpty())
1955             url.setScheme(nProto);
1956     }
1957 
1958     if (index.isValid()) {
1959         SvnItemModelNode *node = static_cast<SvnItemModelNode *>(index.internalPointer());
1960         target = node->fullName();
1961     } else {
1962         target = baseUri();
1963     }
1964     if (action == Qt::MoveAction) {
1965         m_Data->m_Model->svnWrapper()->makeMove(lst, target);
1966     } else if (action == Qt::CopyAction) {
1967         m_Data->m_Model->svnWrapper()->makeCopy(lst, target, (isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision()));
1968     }
1969     refreshCurrentTree();
1970 }
1971 
1972 void MainTreeWidget::slotUrlDropped(const QList<QUrl> &_lst, Qt::DropAction action, const QModelIndex &index, bool intern)
1973 {
1974     if (_lst.isEmpty()) {
1975         return;
1976     }
1977     if (intern) {
1978         internalDrop(_lst, action, index);
1979         return;
1980     }
1981     QUrl target;
1982     if (index.isValid()) {
1983         SvnItemModelNode *node = static_cast<SvnItemModelNode *>(index.internalPointer());
1984         target = node->Url();
1985     } else {
1986         target = baseUriAsUrl();
1987     }
1988 
1989     if (baseUri().isEmpty()) {
1990         openUrl(_lst[0]);
1991         return;
1992     }
1993     QString path = _lst[0].path();
1994     QFileInfo fi(path);
1995     if (!isWorkingCopy()) {
1996         if (!fi.isDir()) {
1997             target.setPath(target.path() + QLatin1Char('/') + _lst[0].fileName());
1998         }
1999         slotImportIntoDir(_lst[0].toLocalFile(), target, fi.isDir());
2000     } else {
2001         WidgetBlockStack w(this);
2002         KIO::Job *job = KIO::copy(_lst, target);
2003         connect(job, &KJob::result, this, &MainTreeWidget::slotCopyFinished);
2004         job->exec();
2005     }
2006 }
2007 
2008 void MainTreeWidget::slotCopyFinished(KJob *_job)
2009 {
2010     KIO::CopyJob *job = dynamic_cast<KIO::CopyJob *>(_job);
2011     if (!job) {
2012         return;
2013     }
2014     bool ok = true;
2015     if (job->error()) {
2016         KJobWidgets::setWindow(job, this);
2017         job->uiDelegate()->showErrorMessage();
2018         ok = false;
2019     }
2020     if (ok) {
2021         const QList<QUrl> lst = job->srcUrls();
2022         const QString base = job->destUrl().toLocalFile() + QLatin1Char('/');
2023         svn::Paths tmp;
2024         tmp.reserve(lst.size());
2025         for (const QUrl &url : lst)
2026             tmp.push_back(svn::Path(base + url.fileName()));
2027 
2028         m_Data->m_Model->svnWrapper()->addItems(tmp, svn::DepthInfinity);
2029     }
2030     refreshCurrentTree();
2031 }
2032 
2033 void MainTreeWidget::stopLogCache()
2034 {
2035     QAction *temp = filesActions()->action(QStringLiteral("update_log_cache"));
2036     m_Data->m_Model->svnWrapper()->stopFillCache();
2037     if (temp) {
2038         temp->setText(i18n("Update log cache"));
2039     }
2040 }
2041 
2042 void MainTreeWidget::slotUpdateLogCache()
2043 {
2044     if (baseUri().length() > 0 && m_Data->m_Model->svnWrapper()->doNetworking()) {
2045         QAction *temp = filesActions()->action(QStringLiteral("update_log_cache"));
2046         if (!m_Data->m_Model->svnWrapper()->threadRunning(SvnActions::fillcachethread)) {
2047             m_Data->m_Model->svnWrapper()->startFillCache(baseUri());
2048             if (temp) {
2049                 temp->setText(i18n("Stop updating the log cache"));
2050             }
2051         } else {
2052             m_Data->m_Model->svnWrapper()->stopFillCache();
2053             if (temp) {
2054                 temp->setText(i18n("Update log cache"));
2055             }
2056         }
2057     }
2058 }
2059 
2060 void MainTreeWidget::slotMkBaseDirs()
2061 {
2062     bool isopen = !baseUri().isEmpty();
2063     if (!isopen) {
2064         return;
2065     }
2066     QString parentDir = baseUri();
2067     svn::Paths targets;
2068     targets.append(svn::Path(parentDir + QLatin1String("/trunk")));
2069     targets.append(svn::Path(parentDir + QLatin1String("/branches")));
2070     targets.append(svn::Path(parentDir + QLatin1String("/tags")));
2071     QString msg = i18n("Automatic generated base layout by kdesvn");
2072     isopen = m_Data->m_Model->svnWrapper()->makeMkdir(svn::Targets(targets), msg);
2073     if (isopen) {
2074         refreshCurrentTree();
2075     }
2076 }
2077 
2078 void MainTreeWidget::slotMkdir()
2079 {
2080     SvnItemModelNode *k = SelectedNode();
2081     QString parentDir;
2082     if (k) {
2083         if (!k->isDir()) {
2084             KMessageBox::error(nullptr, i18n("May not make subdirectories of a file"));
2085             return;
2086         }
2087         parentDir = k->fullName();
2088     } else {
2089         parentDir = baseUri();
2090     }
2091     QString ex = m_Data->m_Model->svnWrapper()->makeMkdir(parentDir);
2092     if (!ex.isEmpty()) {
2093         m_Data->m_Model->refreshDirnode(static_cast<SvnItemModelNodeDir *>(k), true, true);
2094     }
2095 }
2096 
2097 void MainTreeWidget::slotRename()
2098 {
2099     copy_move(true);
2100 }
2101 void MainTreeWidget::slotCopy()
2102 {
2103     copy_move(false);
2104 }
2105 
2106 void MainTreeWidget::copy_move(bool move)
2107 {
2108     if (isWorkingCopy() && SelectedNode() == m_Data->m_Model->firstRootChild()) {
2109         return;
2110     }
2111     bool ok;
2112     SvnItemModelNode *which = SelectedNode();
2113     if (!which) {
2114         return;
2115     }
2116     QString nName = CopyMoveView_impl::getMoveCopyTo(&ok, move, which->fullName(), baseUri(), this);
2117     if (!ok) {
2118         return;
2119     }
2120     if (move) {
2121         m_Data->m_Model->svnWrapper()->makeMove(which->fullName(), nName);
2122     } else {
2123         m_Data->m_Model->svnWrapper()->makeCopy(which->fullName(), nName, isWorkingCopy() ? svn::Revision::HEAD : baseRevision());
2124     }
2125 }
2126 
2127 void MainTreeWidget::slotCleanupAction()
2128 {
2129     if (!isWorkingCopy()) {
2130         return;
2131     }
2132     SvnItemModelNode *which = SelectedNode();
2133     if (!which) {
2134         which = m_Data->m_Model->firstRootChild();
2135     }
2136     if (!which || !which->isDir()) {
2137         return;
2138     }
2139     if (m_Data->m_Model->svnWrapper()->makeCleanup(which->fullName())) {
2140         which->refreshStatus(true);
2141     }
2142 }
2143 
2144 void MainTreeWidget::slotMergeRevisions()
2145 {
2146     if (!isWorkingCopy()) {
2147         return;
2148     }
2149     SvnItemModelNode *which = SelectedNode();
2150     if (!which) {
2151         return;
2152     }
2153     bool force, dry, rec, irelated, useExternal, allowmixedrevs;
2154     Rangeinput_impl::revision_range range;
2155     if (!MergeDlg_impl::getMergeRange(range, &force, &rec, &irelated, &dry, &useExternal, &allowmixedrevs, this)) {
2156         return;
2157     }
2158     if (!useExternal) {
2159         m_Data->m_Model->svnWrapper()->slotMergeWcRevisions(which->fullName(), range.first, range.second, rec, !irelated, force, dry, allowmixedrevs);
2160     } else {
2161         m_Data->m_Model->svnWrapper()->slotMergeExternal(which->fullName(),
2162                                                          which->fullName(),
2163                                                          which->fullName(),
2164                                                          range.first,
2165                                                          range.second,
2166                                                          isWorkingCopy() ? svn::Revision::UNDEFINED : m_Data->m_remoteRevision,
2167                                                          rec);
2168     }
2169     refreshItem(which);
2170     if (which->isDir()) {
2171         m_Data->m_Model->refreshDirnode(static_cast<SvnItemModelNodeDir *>(which), true, false);
2172     }
2173 }
2174 
2175 void MainTreeWidget::slotMerge()
2176 {
2177     SvnItemModelNode *which = SelectedNode();
2178     QString src1, src2, target;
2179     if (isWorkingCopy()) {
2180         if (m_Data->merge_Target.isEmpty()) {
2181             target = which ? which->fullName() : baseUri();
2182         } else {
2183             target = m_Data->merge_Target;
2184         }
2185         src1 = m_Data->merge_Src1;
2186     } else {
2187         if (m_Data->merge_Src1.isEmpty()) {
2188             src1 = which ? which->fullName() : baseUri();
2189         } else {
2190             src1 = m_Data->merge_Src1;
2191         }
2192         target = m_Data->merge_Target;
2193     }
2194     src2 = m_Data->merge_Src2;
2195     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("merge_dialog")));
2196     dlg->setWindowTitle(i18nc("@title:window", "Merge"));
2197     dlg->setWithCancelButton();
2198     dlg->setHelp(QLatin1String("merging-items"));
2199     MergeDlg_impl *ptr(new MergeDlg_impl(dlg));
2200     ptr->setDest(target);
2201     ptr->setSrc1(src1);
2202     ptr->setSrc2(src1);
2203     dlg->addWidget(ptr);
2204     if (dlg->exec() == QDialog::Accepted) {
2205         src1 = ptr->Src1();
2206         src2 = ptr->Src2();
2207         if (src2.isEmpty()) {
2208             src2 = src1;
2209         }
2210         target = ptr->Dest();
2211         m_Data->merge_Src2 = src2;
2212         m_Data->merge_Src1 = src1;
2213         m_Data->merge_Target = target;
2214         bool force = ptr->force();
2215         bool dry = ptr->dryrun();
2216         bool rec = ptr->recursive();
2217         bool irelated = ptr->ignorerelated();
2218         bool useExternal = ptr->useExtern();
2219         bool allowmixedrevs = ptr->allowmixedrevs();
2220         bool recordOnly = ptr->recordOnly();
2221         Rangeinput_impl::revision_range range = ptr->getRange();
2222         bool reintegrate = ptr->reintegrate();
2223         if (!useExternal) {
2224             m_Data->m_Model->svnWrapper()->slotMerge(src1,
2225                                                      src2,
2226                                                      target,
2227                                                      range.first,
2228                                                      range.second,
2229                                                      isWorkingCopy() ? svn::Revision::UNDEFINED : m_Data->m_remoteRevision,
2230                                                      rec,
2231                                                      !irelated,
2232                                                      force,
2233                                                      dry,
2234                                                      recordOnly,
2235                                                      reintegrate,
2236                                                      allowmixedrevs);
2237         } else {
2238             m_Data->m_Model->svnWrapper()
2239                 ->slotMergeExternal(src1, src2, target, range.first, range.second, isWorkingCopy() ? svn::Revision::UNDEFINED : m_Data->m_remoteRevision, rec);
2240         }
2241         if (isWorkingCopy()) {
2242             //            refreshItem(which);
2243             //            refreshRecursive(which);
2244             refreshCurrentTree();
2245         }
2246     }
2247     delete dlg;
2248     enableActions();
2249 }
2250 
2251 void MainTreeWidget::slotRelocate()
2252 {
2253     if (!isWorkingCopy()) {
2254         return;
2255     }
2256     SvnItem *k = SelectedOrMain();
2257     if (!k) {
2258         KMessageBox::error(nullptr, i18n("Error getting entry to relocate"));
2259         return;
2260     }
2261     const QString path = k->fullName();
2262     const QUrl fromUrl = k->Url();
2263     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("relocate_dlg")));
2264     dlg->setWindowTitle(i18nc("@title:window", "Relocate Path %1", path));
2265     dlg->setWithCancelButton();
2266     CheckoutInfo_impl *ptr(new CheckoutInfo_impl(dlg));
2267     ptr->setStartUrl(fromUrl);
2268     ptr->disableAppend(true);
2269     ptr->disableTargetDir(true);
2270     ptr->disableRange(true);
2271     ptr->disableOpen(true);
2272     ptr->hideDepth(true);
2273     ptr->hideOverwrite(true);
2274     dlg->addWidget(ptr);
2275     bool done = false;
2276     if (dlg->exec() == QDialog::Accepted) {
2277         if (!ptr->reposURL().isValid()) {
2278             KMessageBox::error(QApplication::activeModalWidget(), i18n("Invalid url given!"), i18n("Relocate path %1", path));
2279             delete dlg;
2280             return;
2281         }
2282         done = m_Data->m_Model->svnWrapper()->makeRelocate(fromUrl, ptr->reposURL(), path, ptr->overwrite(), ptr->ignoreExternals());
2283     }
2284     delete dlg;
2285     if (done) {
2286         refreshItem(k->sItem());
2287     }
2288 }
2289 
2290 void MainTreeWidget::slotImportDirsIntoCurrent()
2291 {
2292     slotImportIntoCurrent(true);
2293 }
2294 
2295 /*!
2296 \fn MainTreeWidget::slotImportIntoCurrent()
2297 */
2298 void MainTreeWidget::slotImportIntoCurrent(bool dirs)
2299 {
2300     if (selectionCount() > 1) {
2301         KMessageBox::error(this, i18n("Cannot import into multiple targets"));
2302         return;
2303     }
2304     QUrl targetDir;
2305     if (selectionCount() == 0) {
2306         if (isNetworked())
2307             targetDir = QUrl(baseUri());
2308         else
2309             targetDir = QUrl::fromLocalFile(baseUri());
2310     } else {
2311         targetDir = SelectedNode()->Url();
2312     }
2313     QString source;
2314     if (dirs) {
2315         source = QFileDialog::getExistingDirectory(this, i18n("Import files from folder"));
2316     } else {
2317         source = QFileDialog::getOpenFileName(this, i18n("Import file"), QString());
2318     }
2319 
2320     slotImportIntoDir(source, targetDir, dirs);
2321 }
2322 
2323 void MainTreeWidget::slotImportIntoDir(const QString &source, const QUrl &_targetUri, bool dirs)
2324 {
2325     QString sourceUri = source;
2326     while (sourceUri.endsWith(QLatin1Char('/'))) {
2327         sourceUri.chop(1);
2328     }
2329     if (sourceUri.isEmpty()) {
2330         return;
2331     }
2332 
2333     if (_targetUri.isEmpty()) {
2334         return;
2335     }
2336     QUrl targetUri(_targetUri);
2337 
2338     QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("import_log_msg")));
2339     dlg->setWindowTitle(i18nc("@title:window", "Import Log"));
2340     dlg->setWithCancelButton();
2341     Commitmsg_impl *ptr = nullptr;
2342     Importdir_logmsg *ptr2 = nullptr;
2343     if (dirs) {
2344         ptr2 = new Importdir_logmsg(dlg);
2345         ptr2->createDirboxDir(QLatin1Char('"') + QFileInfo(sourceUri).fileName() + QLatin1Char('"'));
2346         ptr = ptr2;
2347     } else {
2348         ptr = new Commitmsg_impl(dlg);
2349     }
2350     ptr->initHistory();
2351     dlg->addWidget(ptr);
2352     if (dlg->exec() != QDialog::Accepted) {
2353         if (dlg) {
2354             ptr->saveHistory(true);
2355             delete dlg;
2356         }
2357         return;
2358     }
2359 
2360     QString logMessage = ptr->getMessage();
2361     svn::Depth rec = ptr->getDepth();
2362     ptr->saveHistory(false);
2363 
2364     if (dirs && ptr2 && ptr2->createDir()) {
2365         targetUri.setPath(targetUri.path() + QLatin1Char('/') + QFileInfo(sourceUri).fileName());
2366     }
2367     if (ptr2) {
2368         m_Data->m_Model->svnWrapper()->slotImport(sourceUri, targetUri, logMessage, rec, ptr2->noIgnore(), ptr2->ignoreUnknownNodes());
2369     } else {
2370         m_Data->m_Model->svnWrapper()->slotImport(sourceUri, targetUri, logMessage, rec, false, false);
2371     }
2372     if (!isWorkingCopy()) {
2373         if (selectionCount() == 0) {
2374             refreshCurrentTree();
2375         } else {
2376             m_Data->m_Model->refreshItem(SelectedNode());
2377         }
2378     }
2379     delete dlg;
2380 }
2381 
2382 void MainTreeWidget::slotChangeToRepository()
2383 {
2384     if (!isWorkingCopy()) {
2385         return;
2386     }
2387     SvnItemModelNode *k = m_Data->m_Model->firstRootChild();
2388     /* huh... */
2389     if (!k) {
2390         return;
2391     }
2392     svn::InfoEntry i;
2393     if (!m_Data->m_Model->svnWrapper()->singleInfo(k->Url().toString(), svn::Revision::UNDEFINED, i)) {
2394         return;
2395     }
2396     if (i.reposRoot().isEmpty()) {
2397         KMessageBox::error(QApplication::activeModalWidget(), i18n("Could not retrieve repository of working copy."), i18n("SVN Error"));
2398     } else {
2399         emit sigSwitchUrl(i.reposRoot());
2400     }
2401 }
2402 
2403 void MainTreeWidget::slotCheckNewItems()
2404 {
2405     if (!isWorkingCopy()) {
2406         KMessageBox::error(nullptr, i18n("Only in working copy possible."), i18n("Error"));
2407         return;
2408     }
2409     if (selectionCount() > 1) {
2410         KMessageBox::error(nullptr, i18n("Only on single folder possible"), i18n("Error"));
2411         return;
2412     }
2413     SvnItem *w = SelectedOrMain();
2414     if (!w) {
2415         KMessageBox::error(nullptr, i18n("Sorry - internal error"), i18n("Error"));
2416         return;
2417     }
2418     m_Data->m_Model->svnWrapper()->checkAddItems(w->fullName(), true);
2419 }
2420 
2421 void MainTreeWidget::refreshCurrent(SvnItem *cur)
2422 {
2423     if (!cur || !cur->sItem()) {
2424         refreshCurrentTree();
2425         return;
2426     }
2427     QCoreApplication::processEvents();
2428     setUpdatesEnabled(false);
2429     if (cur->isDir()) {
2430         m_Data->m_Model->refreshDirnode(static_cast<SvnItemModelNodeDir *>(cur->sItem()));
2431     } else {
2432         m_Data->m_Model->refreshItem(cur->sItem());
2433     }
2434     setUpdatesEnabled(true);
2435     m_TreeView->viewport()->repaint();
2436 }
2437 
2438 void MainTreeWidget::slotReinitItem(SvnItem *item)
2439 {
2440     if (!item) {
2441         return;
2442     }
2443     SvnItemModelNode *k = item->sItem();
2444     if (!k) {
2445         return;
2446     }
2447     m_Data->m_Model->refreshItem(k);
2448     if (k->isDir()) {
2449         m_Data->m_Model->clearNodeDir(static_cast<SvnItemModelNodeDir *>(k));
2450     }
2451 }
2452 
2453 void MainTreeWidget::keyPressEvent(QKeyEvent *event)
2454 {
2455     if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !event->isAutoRepeat()) {
2456         QModelIndex index = SelectedIndex();
2457         if (index.isValid()) {
2458             itemActivated(index, true);
2459             return;
2460         }
2461     }
2462     QWidget::keyPressEvent(event);
2463 }
2464 
2465 void MainTreeWidget::slotItemExpanded(const QModelIndex &)
2466 {
2467 }
2468 
2469 void MainTreeWidget::slotItemsInserted(const QModelIndex &)
2470 {
2471     m_Data->m_resizeColumnsTimer.start(50);
2472 }
2473 
2474 void MainTreeWidget::slotDirSelectionChanged(const QItemSelection &_item, const QItemSelection &)
2475 {
2476     const QModelIndexList _indexes = _item.indexes();
2477     switch (DirselectionCount()) {
2478     case 1:
2479         m_DirTreeView->setStatusTip(i18n("Hold Ctrl key while click on selected item for unselect"));
2480         break;
2481     case 2:
2482         m_DirTreeView->setStatusTip(i18n("See context menu for more actions"));
2483         break;
2484     case 0:
2485         m_DirTreeView->setStatusTip(i18n("Click for navigate"));
2486         break;
2487     default:
2488         m_DirTreeView->setStatusTip(i18n("Navigation"));
2489         break;
2490     }
2491     if (_indexes.size() >= 1) {
2492         const QModelIndex _t = m_Data->srcDirInd(_indexes.at(0));
2493         if (m_Data->m_Model->canFetchMore(_t)) {
2494             WidgetBlockStack st(m_TreeView);
2495             WidgetBlockStack st2(m_DirTreeView);
2496             m_Data->m_Model->fetchMore(_t);
2497         }
2498         if (Kdesvnsettings::show_navigation_panel()) {
2499             m_TreeView->setRootIndex(m_Data->m_SortModel->mapFromSource(_t));
2500         }
2501         // Display relative path (including name of the checkout) in the titlebar
2502         auto item = m_Data->m_Model->nodeForIndex(_t);
2503         if (item) {
2504             const QString repoBasePath = baseUri();
2505             const QString relativePath = item->fullName().mid(repoBasePath.lastIndexOf('/') + 1);
2506             emit changeCaption(relativePath);
2507         }
2508 
2509     } else {
2510         checkSyncTreeModel();
2511     }
2512     if (m_TreeView->selectionModel()->hasSelection()) {
2513         m_TreeView->selectionModel()->clearSelection();
2514     } else {
2515         enableActions();
2516     }
2517     resizeAllColumns();
2518 }
2519 
2520 void MainTreeWidget::checkSyncTreeModel()
2521 {
2522     // make sure that the treeview shows the contents of the selected directory in the directory tree view
2523     // it can go out of sync when the dir tree model has no current index - then we use the first entry
2524     // or when the filter settings are changed
2525     QModelIndex curIdxDir = m_DirTreeView->currentIndex();
2526     if (!curIdxDir.isValid() && m_Data->m_DirSortModel->columnCount() > 0) {
2527         m_DirTreeView->setCurrentIndex(m_Data->m_DirSortModel->index(0, 0));
2528         curIdxDir = m_DirTreeView->currentIndex();
2529     }
2530     const QModelIndex curIdxBase = m_Data->srcDirInd(curIdxDir);
2531     m_TreeView->setRootIndex(m_Data->m_SortModel->mapFromSource(curIdxBase));
2532 }
2533 
2534 void MainTreeWidget::slotCommit()
2535 {
2536     m_Data->m_Model->svnWrapper()->doCommit(SelectionList());
2537 }
2538 
2539 void MainTreeWidget::slotDirCommit()
2540 {
2541     m_Data->m_Model->svnWrapper()->doCommit(DirSelectionList());
2542 }
2543 
2544 void MainTreeWidget::slotDirUpdate()
2545 {
2546     const SvnItemList which = DirSelectionList();
2547     svn::Paths what;
2548     if (which.isEmpty()) {
2549         what.append(svn::Path(baseUri()));
2550     } else {
2551         what.reserve(which.size());
2552         for (const SvnItem *item : which)
2553             what.append(svn::Path(item->fullName()));
2554     }
2555     m_Data->m_Model->svnWrapper()->makeUpdate(svn::Targets(what), svn::Revision::HEAD, svn::DepthUnknown);
2556 }
2557 
2558 void MainTreeWidget::slotRefreshItem(const QString &path)
2559 {
2560     const QModelIndex idx = m_Data->m_Model->findIndex(path);
2561     if (!idx.isValid())
2562         return;
2563     m_Data->m_Model->emitDataChangedRow(idx);
2564 }
2565 
2566 void MainTreeWidget::checkUseNavigation(bool startup)
2567 {
2568     bool use = Kdesvnsettings::show_navigation_panel();
2569     if (use) {
2570         checkSyncTreeModel();
2571     } else {
2572         // tree view is the only visible view, make sure to display all
2573         m_TreeView->setRootIndex(QModelIndex());
2574         m_TreeView->expand(QModelIndex());
2575     }
2576     m_TreeView->setExpandsOnDoubleClick(!use);
2577     m_TreeView->setRootIsDecorated(!use);
2578     m_TreeView->setItemsExpandable(!use);
2579     QList<int> si;
2580     if (use) {
2581         if (!startup) {
2582             si = m_ViewSplitter->sizes();
2583             if (si.size() == 2 && si[0] < 5) {
2584                 si[0] = 200;
2585                 m_ViewSplitter->setSizes(si);
2586             }
2587         }
2588     } else {
2589         si << 0 << 300;
2590         m_ViewSplitter->setSizes(si);
2591     }
2592 }
2593 
2594 void MainTreeWidget::slotRepositorySettings()
2595 {
2596     if (baseUri().length() == 0) {
2597         return;
2598     }
2599     svn::InfoEntry inf;
2600     if (!m_Data->m_Model->svnWrapper()->singleInfo(baseUri(), baseRevision(), inf)) {
2601         return;
2602     }
2603     if (inf.reposRoot().isEmpty()) {
2604         KMessageBox::error(QApplication::activeModalWidget(), i18n("Could not retrieve repository."), i18n("SVN Error"));
2605     } else {
2606         DbSettings::showSettings(inf.reposRoot().toString(), this);
2607     }
2608 }
2609 
2610 void MainTreeWidget::slotRightProperties()
2611 {
2612     SvnItem *k = Selected();
2613     if (!k) {
2614         return;
2615     }
2616     m_Data->m_Model->svnWrapper()->editProperties(k, isWorkingCopy() ? svn::Revision::WORKING : svn::Revision::HEAD);
2617 }
2618 
2619 void MainTreeWidget::slotLeftProperties()
2620 {
2621     SvnItem *k = DirSelected();
2622     if (!k) {
2623         return;
2624     }
2625     m_Data->m_Model->svnWrapper()->editProperties(k, isWorkingCopy() ? svn::Revision::WORKING : svn::Revision::HEAD);
2626 }
2627 
2628 void MainTreeWidget::slotDirRecProperty()
2629 {
2630     SvnItem *k = DirSelected();
2631     if (!k) {
2632         return;
2633     }
2634     KMessageBox::information(this, i18n("Not yet implemented"), i18n("Edit property recursively"));
2635 }
2636 
2637 #include "moc_maintreewidget.cpp"