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 }