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