File indexing completed on 2024-05-12 17:16:13

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