1 /***************************************************************************
2 * Copyright (C) 2008 by Rajko Albrecht ral@alwins-world.de *
3 * http://kdesvn.alwins-world.de/ *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 #include "maintreewidget.h"
22 #include "models/svnitemmodel.h"
23 #include "models/svnitemnode.h"
24 #include "models/svnsortfilter.h"
25 #include "models/svndirsortfilter.h"
26 #include "database/dbsettings.h"
27 #include "cursorstack.h"
28 #include "svnactions.h"
29 #include "copymoveview_impl.h"
30 #include "mergedlg_impl.h"
31 #include "checkoutinfo_impl.h"
32 #include "importdir_logmsg.h"
33 #include "settings/kdesvnsettings.h"
34 #include "helpers/sshagent.h"
35 #include "svnqt/targets.h"
36 #include "svnqt/url.h"
37 #include "fronthelpers/rangeinput_impl.h"
38 #include "fronthelpers/widgetblockstack.h"
39 #include "fronthelpers/fronthelpers.h"
40 #include "ksvnwidgets/commitmsg_impl.h"
41 #include "ksvnwidgets/deleteform.h"
42 #include "helpers/kdesvn_debug.h"
43 #include "opencontextmenu.h"
44 #include "EditIgnorePattern.h"
45
46 #include <kjobwidgets.h>
47 #include <kjobuidelegate.h>
48 #include <kmessagebox.h>
49 #include <kactioncollection.h>
50 #include <kauthorized.h>
51 #include <kmimetypetrader.h>
52 #include <kio/deletejob.h>
53 #include <kio/copyjob.h>
54 #include <unistd.h>
55
56 #include <QApplication>
57 #include <QCheckBox>
58 #include <QKeyEvent>
59 #include <QUrlQuery>
60 #include <QTimer>
61
62 class MainTreeWidgetData
63 {
64 public:
MainTreeWidgetData()65 MainTreeWidgetData()
66 {
67 m_Collection = nullptr;
68 m_Model = nullptr;
69 m_SortModel = nullptr;
70 m_DirSortModel = nullptr;
71 m_remoteRevision = svn::Revision::UNDEFINED;
72 }
73
~MainTreeWidgetData()74 ~MainTreeWidgetData()
75 {
76 delete m_Model;
77 delete m_SortModel;
78 delete m_DirSortModel;
79 }
80
srcInd(const QModelIndex & ind)81 QModelIndex srcInd(const QModelIndex &ind)
82 {
83 return m_SortModel->mapToSource(ind);
84 }
85
srcDirInd(const QModelIndex & ind)86 QModelIndex srcDirInd(const QModelIndex &ind)
87 {
88 return m_DirSortModel->mapToSource(ind);
89 }
90
sourceNode(const QModelIndex & index,bool left)91 SvnItemModelNode *sourceNode(const QModelIndex &index, bool left)
92 {
93 if (!index.isValid()) {
94 return nullptr;
95 }
96 QModelIndex ind = left ? m_DirSortModel->mapToSource(index) : m_SortModel->mapToSource(index);
97 if (ind.isValid()) {
98 return static_cast<SvnItemModelNode *>(ind.internalPointer());
99 }
100 return nullptr;
101 }
102
103 KActionCollection *m_Collection;
104 SvnItemModel *m_Model;
105 SvnSortFilterProxy *m_SortModel;
106 SvnDirSortFilterProxy *m_DirSortModel;
107 svn::Revision m_remoteRevision;
108 QString merge_Target, merge_Src2, merge_Src1;
109
110 QTimer m_TimeModified, m_TimeUpdates, m_resizeColumnsTimer;
111 };
112
MainTreeWidget(KActionCollection * aCollection,QWidget * parent,Qt::WindowFlags f)113 MainTreeWidget::MainTreeWidget(KActionCollection *aCollection, QWidget *parent, Qt::WindowFlags f)
114 : QWidget(parent, f), m_Data(new MainTreeWidgetData)
115 {
116 setupUi(this);
117 setFocusPolicy(Qt::StrongFocus);
118 m_TreeView->setFocusPolicy(Qt::StrongFocus);
119 m_Data->m_Collection = aCollection;
120 m_Data->m_SortModel = new SvnSortFilterProxy();
121 m_Data->m_SortModel->setDynamicSortFilter(true);
122 m_Data->m_SortModel->setSortRole(SORT_ROLE);
123 m_Data->m_SortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
124 m_Data->m_SortModel->sort(0);
125 m_TreeView->setModel(m_Data->m_SortModel);
126 m_TreeView->sortByColumn(0, Qt::AscendingOrder);
127 m_Data->m_Model = new SvnItemModel(this);
128 m_Data->m_SortModel->setSourceModel(m_Data->m_Model);
129
130 m_Data->m_DirSortModel = new SvnDirSortFilterProxy();
131 m_Data->m_DirSortModel->setDynamicSortFilter(true);
132 m_Data->m_DirSortModel->setSortRole(SORT_ROLE);
133 m_Data->m_DirSortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
134
135 m_DirTreeView->setModel(m_Data->m_DirSortModel);
136 m_Data->m_DirSortModel->setSourceModel(m_Data->m_Model);
137
138 connect(m_TreeView->selectionModel(),
139 &QItemSelectionModel::selectionChanged,
140 this, &MainTreeWidget::slotSelectionChanged);
141
142 connect(m_DirTreeView->selectionModel(),
143 &QItemSelectionModel::selectionChanged,
144 this, &MainTreeWidget::slotDirSelectionChanged);
145
146 connect(m_Data->m_Model->svnWrapper(), &SvnActions::clientException, this, &MainTreeWidget::slotClientException);
147 connect(m_Data->m_Model, &SvnItemModel::clientException, this, &MainTreeWidget::slotClientException);
148 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sendNotify, this, &MainTreeWidget::slotNotifyMessage);
149 connect(m_Data->m_Model->svnWrapper(), &SvnActions::reinitItem, this, &MainTreeWidget::slotReinitItem);
150 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigRefreshAll, this, &MainTreeWidget::refreshCurrentTree);
151 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigRefreshCurrent, this, &MainTreeWidget::refreshCurrent);
152 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigRefreshItem, this, &MainTreeWidget::slotRefreshItem);
153 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigGotourl, this, &MainTreeWidget::_openUrl);
154 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigCacheStatus, this, &MainTreeWidget::sigCacheStatus);
155 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigThreadsChanged, this, &MainTreeWidget::enableActions);
156 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigCacheDataChanged, this, &MainTreeWidget::slotCacheDataChanged);
157
158 connect(m_Data->m_Model->svnWrapper(), &SvnActions::sigExtraStatusMessage, this, &MainTreeWidget::sigExtraStatusMessage);
159
160 connect(m_Data->m_Model, &SvnItemModel::urlDropped,
161 this, &MainTreeWidget::slotUrlDropped);
162
163 connect(m_Data->m_Model, &SvnItemModel::itemsFetched, this, &MainTreeWidget::slotItemsInserted);
164
165 m_TreeView->sortByColumn(0, Qt::AscendingOrder);
166 m_DirTreeView->sortByColumn(0, Qt::AscendingOrder);
167
168 checkUseNavigation(true);
169 setupActions();
170
171 m_Data->m_TimeModified.setParent(this);
172 connect(&(m_Data->m_TimeModified), &QTimer::timeout, this, &MainTreeWidget::slotCheckModified);
173 m_Data->m_TimeUpdates.setParent(this);
174 connect(&(m_Data->m_TimeUpdates), &QTimer::timeout, this, &MainTreeWidget::slotCheckUpdates);
175 m_Data->m_resizeColumnsTimer.setSingleShot(true);
176 m_Data->m_resizeColumnsTimer.setParent(this);
177 connect(&(m_Data->m_resizeColumnsTimer), &QTimer::timeout, this, &MainTreeWidget::resizeAllColumns);
178 }
179
~MainTreeWidget()180 MainTreeWidget::~MainTreeWidget()
181 {
182 // make sure to not get signals which affect the mmi
183 m_Data->m_Model->disconnect(this);
184 m_Data->m_Model->svnWrapper()->disconnect(this);
185 delete m_Data;
186 }
187
_openUrl(const QUrl & url)188 void MainTreeWidget::_openUrl(const QUrl &url)
189 {
190 openUrl(url, true);
191 }
192
resizeAllColumns()193 void MainTreeWidget::resizeAllColumns()
194 {
195 m_TreeView->resizeColumnToContents(SvnItemModel::Name);
196 m_TreeView->resizeColumnToContents(SvnItemModel::Status);
197 m_TreeView->resizeColumnToContents(SvnItemModel::LastRevision);
198 m_TreeView->resizeColumnToContents(SvnItemModel::LastAuthor);
199 m_TreeView->resizeColumnToContents(SvnItemModel::LastDate);
200 m_DirTreeView->resizeColumnToContents(SvnItemModel::Name);
201 }
202
openUrl(const QUrl & url,bool noReinit)203 bool MainTreeWidget::openUrl(const QUrl &url, bool noReinit)
204 {
205
206 #ifdef DEBUG_TIMER
207 QTime _counttime;
208 _counttime.start();
209 #endif
210
211 CursorStack a;
212 m_Data->m_Model->svnWrapper()->killallThreads();
213 clear();
214 emit sigProplist(svn::PathPropertiesMapListPtr(new svn::PathPropertiesMapList()), false, false, QString());
215
216 if (!noReinit) {
217 m_Data->m_Model->svnWrapper()->reInitClient();
218 }
219
220 QUrl _url(url);
221 const QString proto = svn::Url::transformProtokoll(url.scheme());
222 _url = _url.adjusted(QUrl::StripTrailingSlash|QUrl::NormalizePathSegments);
223 _url.setScheme(proto);
224
225 const QString baseUriString = _url.url(QUrl::StripTrailingSlash);
226 const QVector<QStringRef> s = baseUriString.splitRef(QLatin1Char('?'));
227 if (s.size() > 1) {
228 setBaseUri(s.first().toString());
229 } else {
230 setBaseUri(baseUriString);
231 }
232 setWorkingCopy(false);
233 setNetworked(false);
234 m_Data->m_remoteRevision = svn::Revision::HEAD;
235
236 if (QLatin1String("svn+file") == url.scheme()) {
237 setBaseUri(url.path());
238 } else {
239 if (url.isLocalFile()) {
240 QFileInfo fi(url.path());
241 if (fi.exists() && fi.isSymLink()) {
242 const QString sl = fi.symLinkTarget();
243 if (sl.startsWith(QLatin1Char('/'))) {
244 setBaseUri(sl);
245 } else {
246 fi.setFile(fi.path() + QLatin1Char('/') + sl);
247 setBaseUri(fi.absoluteFilePath());
248 }
249 } else {
250 setBaseUri(url.path());
251 }
252 QUrl _dummy;
253 qCDebug(KDESVN_LOG) << "check if " << baseUri() << " is a local wc ...";
254 if (m_Data->m_Model->svnWrapper()->isLocalWorkingCopy(baseUri(), _dummy)) {
255 setWorkingCopy(true);
256 // make sure a valid path is stored as baseuri
257 setBaseUri(url.toLocalFile());
258 qCDebug(KDESVN_LOG) << "... yes -> " << baseUri();
259 } else {
260 setWorkingCopy(false);
261 // make sure a valid url is stored as baseuri
262 setBaseUri(url.toString());
263 qCDebug(KDESVN_LOG) << "... no -> " << baseUri();
264 }
265 } else {
266 setNetworked(true);
267 if (!Kdesvnsettings::network_on()) {
268 setBaseUri(QString());
269 setNetworked(false);
270 clear();
271 KMessageBox::error(this, i18n("Networked URL to open but networking is disabled."));
272 emit changeCaption(QString());
273 emit sigUrlOpened(false);
274 return false;
275 }
276 }
277 }
278 const QList<QPair<QString, QString>> q = QUrlQuery(url).queryItems();
279 typedef QPair<QString, QString> queryPair;
280 for (const queryPair &p : q) {
281 if (p.first == QLatin1String("rev")) {
282 const QString v = p.second;
283 svn::Revision tmp;
284 m_Data->m_Model->svnWrapper()->svnclient()->url2Revision(v, m_Data->m_remoteRevision, tmp);
285 if (m_Data->m_remoteRevision == svn::Revision::UNDEFINED) {
286 m_Data->m_remoteRevision = svn::Revision::HEAD;
287 }
288 }
289 }
290 if (url.scheme() == QLatin1String("svn+ssh") ||
291 url.scheme() == QLatin1String("ksvn+ssh")) {
292 SshAgent ssh;
293 ssh.addSshIdentities();
294 }
295 m_Data->m_Model->svnWrapper()->clearUpdateCache();
296 if (isWorkingCopy()) {
297 m_Data->m_Model->initDirWatch();
298 }
299 bool result = m_Data->m_Model->checkDirs(baseUri(), nullptr) > -1;
300 if (result && isWorkingCopy()) {
301 m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
302 m_DirTreeView->expandToDepth(0);
303 m_DirTreeView->selectionModel()->select(m_Data->m_DirSortModel->mapFromSource(m_Data->m_Model->firstRootIndex()), QItemSelectionModel::Select);
304 }
305 resizeAllColumns();
306
307 if (!result) {
308 setBaseUri(QString());
309 setNetworked(false);
310 clear();
311 }
312 if (result && isWorkingCopy()) {
313 m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
314 if (Kdesvnsettings::start_updates_check_on_open()) {
315 slotCheckUpdates();
316 }
317 }
318 #ifdef DEBUG_TIMER
319 _counttime.restart();
320 #endif
321
322 if (result && Kdesvnsettings::log_cache_on_open()) {
323 m_Data->m_Model->svnWrapper()->startFillCache(baseUri(), true);
324 }
325 #ifdef DEBUG_TIMER
326 qCDebug(KDESVN_LOG) << "Starting cache " << _counttime.elapsed();
327 _counttime.restart();
328 #endif
329 emit changeCaption(baseUri());
330 emit sigUrlOpened(result);
331 emit sigUrlChanged(baseUriAsUrl());
332 #ifdef DEBUG_TIMER
333 qCDebug(KDESVN_LOG) << "Fired signals " << _counttime.elapsed();
334 _counttime.restart();
335 #endif
336
337 QTimer::singleShot(1, this, &MainTreeWidget::readSupportData);
338 enableActions();
339 #ifdef DEBUG_TIMER
340 qCDebug(KDESVN_LOG) << "Enabled actions " << _counttime.elapsed();
341 #endif
342 /* KNotification * notification=new KNotification("kdesvn-open");
343 notification->setText("Opened url");
344 notification->sendEvent();
345 */
346 return result;
347 }
348
clear()349 void MainTreeWidget::clear()
350 {
351 m_Data->m_Model->clear();
352 }
353
baseRevision() const354 svn::Revision MainTreeWidget::baseRevision()const
355 {
356 return m_Data->m_remoteRevision;
357 }
358
realWidget()359 QWidget *MainTreeWidget::realWidget()
360 {
361 return this;
362 }
363
selectionCount() const364 int MainTreeWidget::selectionCount()const
365 {
366 int count = m_TreeView->selectionModel()->selectedRows(0).count();
367 if (count == 0) {
368 if (m_TreeView->rootIndex().isValid()) {
369 return 1;
370 }
371 }
372 return count;
373 }
374
DirselectionCount() const375 int MainTreeWidget::DirselectionCount()const
376 {
377 return m_DirTreeView->selectionModel()->selectedRows(0).count();
378 }
379
SelectionList() const380 SvnItemList MainTreeWidget::SelectionList()const
381 {
382 SvnItemList ret;
383 const QModelIndexList _mi = m_TreeView->selectionModel()->selectedRows(0);
384 ret.reserve(_mi.size());
385 if (_mi.isEmpty()) {
386 QModelIndex ind = m_TreeView->rootIndex();
387 if (ind.isValid()) {
388 // really! it will remapped to this before setRootIndex! (see below)
389 ret.push_back(m_Data->sourceNode(ind, false));
390 }
391 return ret;
392 }
393 for (int i = 0; i < _mi.count(); ++i) {
394 ret.push_back(m_Data->sourceNode(_mi[i], false));
395 }
396 return ret;
397 }
398
DirSelectionList() const399 SvnItemList MainTreeWidget::DirSelectionList()const
400 {
401 SvnItemList ret;
402 const QModelIndexList _mi = m_DirTreeView->selectionModel()->selectedRows(0);
403 ret.reserve(_mi.size());
404 for (int i = 0; i < _mi.count(); ++i) {
405 ret.push_back(m_Data->sourceNode(_mi[i], true));
406 }
407 return ret;
408 }
409
SelectedIndex() const410 QModelIndex MainTreeWidget::SelectedIndex()const
411 {
412 const QModelIndexList _mi = m_TreeView->selectionModel()->selectedRows(0);
413 if (_mi.count() != 1) {
414 if (_mi.isEmpty()) {
415 const QModelIndex ind = m_TreeView->rootIndex();
416 if (ind.isValid()) {
417 return m_Data->m_SortModel->mapToSource(ind);
418 }
419 }
420 return QModelIndex();
421 }
422 return m_Data->m_SortModel->mapToSource(_mi[0]);
423 }
424
DirSelectedIndex() const425 QModelIndex MainTreeWidget::DirSelectedIndex()const
426 {
427 const QModelIndexList _mi = m_DirTreeView->selectionModel()->selectedRows(0);
428 if (_mi.count() != 1) {
429 return QModelIndex();
430 }
431 return m_Data->m_DirSortModel->mapToSource(_mi[0]);
432 }
433
SelectedNode() const434 SvnItemModelNode *MainTreeWidget::SelectedNode()const
435 {
436 const QModelIndex index = SelectedIndex();
437 if (index.isValid()) {
438 SvnItemModelNode *item = static_cast<SvnItemModelNode *>(index.internalPointer());
439 return item;
440 }
441 return nullptr;
442 }
443
DirSelectedNode() const444 SvnItemModelNode *MainTreeWidget::DirSelectedNode()const
445 {
446 const QModelIndex index = DirSelectedIndex();
447 if (index.isValid()) {
448 SvnItemModelNode *item = static_cast<SvnItemModelNode *>(index.internalPointer());
449 return item;
450 }
451 return nullptr;
452 }
453
slotSelectionChanged(const QItemSelection &,const QItemSelection &)454 void MainTreeWidget::slotSelectionChanged(const QItemSelection &, const QItemSelection &)
455 {
456 enableActions();
457 QTimer::singleShot(100, this, &MainTreeWidget::_propListTimeout);
458 }
459
Selected() const460 SvnItem *MainTreeWidget::Selected()const
461 {
462 return SelectedNode();
463 }
464
DirSelected() const465 SvnItem *MainTreeWidget::DirSelected()const
466 {
467 return DirSelectedNode();
468 }
469
DirSelectedOrMain() const470 SvnItem *MainTreeWidget::DirSelectedOrMain()const
471 {
472 SvnItem *_item = DirSelected();
473 if (_item == nullptr && isWorkingCopy()) {
474 _item = m_Data->m_Model->firstRootChild();
475 }
476 return _item;
477 }
478
SelectedOrMain() const479 SvnItem *MainTreeWidget::SelectedOrMain()const
480 {
481 SvnItem *_item = Selected();
482 if (_item == nullptr && isWorkingCopy()) {
483 _item = m_Data->m_Model->firstRootChild();
484 }
485 return _item;
486 }
487
setupActions()488 void MainTreeWidget::setupActions()
489 {
490 if (!m_Data->m_Collection) {
491 return;
492 }
493 QAction *tmp_action;
494 /* local and remote actions */
495 /* 1. actions on dirs AND files */
496 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()));
497 tmp_action->setIconText(i18n("History"));
498 tmp_action->setStatusTip(i18n("Displays the history log of selected item"));
499 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()));
500 tmp_action->setIconText(i18n("History"));
501 tmp_action->setStatusTip(i18n("Displays the history log of selected item without following copies"));
502
503 tmp_action = add_action(QStringLiteral("make_svn_dir_log_nofollow"), i18n("History of item ignoring copies"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnlog")), this, SLOT(slotDirMakeLogNoFollow()));
504 tmp_action->setIconText(i18n("History"));
505 tmp_action->setStatusTip(i18n("Displays the history log of selected item without following copies"));
506
507 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()));
508 tmp_action->setStatusTip(i18n("Shows history of item as linked tree"));
509 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()));
510 tmp_action->setStatusTip(i18n("Shows history of item as linked tree for a revision range"));
511
512 tmp_action = add_action(QStringLiteral("make_svn_property"), i18n("Properties"), QKeySequence(Qt::CTRL | Qt::Key_P), QIcon(), this, SLOT(slotRightProperties()));
513 tmp_action = add_action(QStringLiteral("make_left_svn_property"), i18n("Properties"), QKeySequence(), QIcon(), this, SLOT(slotLeftProperties()));
514 add_action(QStringLiteral("get_svn_property"), i18n("Display Properties"), QKeySequence(Qt::SHIFT | Qt::CTRL | Qt::Key_P), QIcon(), this, SLOT(slotDisplayProperties()));
515 tmp_action = add_action(QStringLiteral("make_last_change"), i18n("Display last changes"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvndiff")), this, SLOT(slotDisplayLastDiff()));
516 tmp_action->setToolTip(i18n("Display last changes as difference to previous commit."));
517 tmp_action = add_action(QStringLiteral("make_svn_info"), i18n("Details"), QKeySequence(Qt::CTRL | Qt::Key_I), QIcon::fromTheme(QStringLiteral("kdesvninfo")), this, SLOT(slotInfo()));
518 tmp_action->setStatusTip(i18n("Show details about selected item"));
519 tmp_action = add_action(QStringLiteral("make_svn_rename"), i18n("Move"), QKeySequence(Qt::Key_F2), QIcon::fromTheme(QStringLiteral("kdesvnmove")), this, SLOT(slotRename()));
520 tmp_action->setStatusTip(i18n("Moves or renames current item"));
521 tmp_action = add_action(QStringLiteral("make_svn_copy"), i18n("Copy"), QKeySequence(Qt::CTRL | Qt::Key_C), QIcon::fromTheme(QStringLiteral("kdesvncopy")), this, SLOT(slotCopy()));
522 tmp_action->setStatusTip(i18n("Create a copy of current item"));
523 tmp_action = add_action(QStringLiteral("make_check_updates"), i18n("Check for updates"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncheckupdates")), this, SLOT(slotCheckUpdates()));
524 tmp_action->setToolTip(i18n("Check if current working copy has items with newer version in repository"));
525 tmp_action->setStatusTip(tmp_action->toolTip());
526 tmp_action->setIconText(i18n("Check updates"));
527
528 /* 2. actions only on files */
529 tmp_action = add_action(QStringLiteral("make_svn_blame"), i18n("Blame"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnblame")), this, SLOT(slotBlame()));
530 tmp_action->setToolTip(i18n("Output the content of specified files or URLs with revision and author information in-line."));
531 tmp_action->setStatusTip(tmp_action->toolTip());
532 tmp_action = add_action(QStringLiteral("make_svn_range_blame"), i18n("Blame range"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnblame")), this, SLOT(slotRangeBlame()));
533 tmp_action->setToolTip(i18n("Output the content of specified files or URLs with revision and author information in-line."));
534 tmp_action->setStatusTip(tmp_action->toolTip());
535
536 tmp_action = add_action(QStringLiteral("make_svn_cat"), i18n("Cat head"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncat")), this, SLOT(slotCat()));
537 tmp_action->setToolTip(i18n("Output the content of specified files or URLs."));
538 tmp_action->setStatusTip(tmp_action->toolTip());
539 tmp_action = add_action(QStringLiteral("make_revisions_cat"), i18n("Cat revision..."), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncat")), this, SLOT(slotRevisionCat()));
540 tmp_action->setToolTip(i18n("Output the content of specified files or URLs at specific revision."));
541 tmp_action->setStatusTip(tmp_action->toolTip());
542
543 tmp_action = add_action(QStringLiteral("make_svn_lock"), i18n("Lock current items"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnlock")), this, SLOT(slotLock()));
544 tmp_action->setToolTip(i18n("Try lock current item against changes from other users"));
545 tmp_action->setStatusTip(tmp_action->toolTip());
546 tmp_action = add_action(QStringLiteral("make_svn_unlock"), i18n("Unlock current items"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnunlock")), this, SLOT(slotUnlock()));
547 tmp_action->setToolTip(i18n("Free existing lock on current item"));
548 tmp_action->setStatusTip(tmp_action->toolTip());
549
550 /* 3. actions only on dirs */
551 tmp_action = add_action(QStringLiteral("make_svn_mkdir"), i18n("New folder"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnnewfolder")), this, SLOT(slotMkdir()));
552 tmp_action->setStatusTip(i18n("Create a new folder"));
553 tmp_action = add_action(QStringLiteral("make_svn_switch"), i18n("Switch repository"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnswitch")), m_Data->m_Model->svnWrapper(), SLOT(slotSwitch()));
554 tmp_action->setToolTip(i18n("Switch repository path of current working copy path (\"svn switch\")"));
555 tmp_action->setStatusTip(tmp_action->toolTip());
556
557 tmp_action = add_action(QStringLiteral("make_svn_relocate"), i18n("Relocate current working copy URL"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnrelocate")), this, SLOT(slotRelocate()));
558 tmp_action->setToolTip(i18n("Relocate URL of current working copy path to other URL"));
559 tmp_action->setStatusTip(tmp_action->toolTip());
560
561 tmp_action = add_action(QStringLiteral("make_check_unversioned"), i18n("Check for unversioned items"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnaddrecursive")), this, SLOT(slotCheckNewItems()));
562 tmp_action->setIconText(i18n("Unversioned"));
563 tmp_action->setToolTip(i18n("Browse folder for unversioned items and add them if wanted."));
564 tmp_action->setStatusTip(tmp_action->toolTip());
565
566 tmp_action = add_action(QStringLiteral("make_switch_to_repo"), i18n("Open repository of working copy"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnrepository")),
567 this, SLOT(slotChangeToRepository()));
568 tmp_action->setToolTip(i18n("Opens the repository the current working copy was checked out from"));
569
570 tmp_action = add_action(QStringLiteral("make_cleanup"), i18n("Cleanup"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncleanup")), this, SLOT(slotCleanupAction()));
571 tmp_action->setToolTip(i18n("Recursively clean up the working copy, removing locks, resuming unfinished operations, etc."));
572 tmp_action = add_action(QStringLiteral("make_import_dirs_into_current"), i18n("Import folders into current"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnimportfolder")),
573 this, SLOT(slotImportDirsIntoCurrent()));
574 tmp_action->setToolTip(i18n("Import folder content into current URL"));
575
576 /* local only actions */
577 /* 1. actions on files AND dirs*/
578 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()));
579 tmp_action->setToolTip(i18n("Adding selected files and/or directories to repository"));
580 tmp_action->setIconText(i18n("Add"));
581 tmp_action = add_action(QStringLiteral("make_svn_addrec"), i18n("Add selected files/dirs recursive"), QKeySequence(Qt::CTRL | Qt::Key_Insert), QIcon::fromTheme(QStringLiteral("kdesvnaddrecursive")),
582 m_Data->m_Model->svnWrapper(), SLOT(slotAddRec()));
583 tmp_action->setToolTip(i18n("Adding selected files and/or directories to repository and all subitems of folders"));
584
585 tmp_action = add_action(QStringLiteral("make_svn_remove"), i18n("Delete selected files/dirs"), QKeySequence(Qt::Key_Delete), QIcon::fromTheme(QStringLiteral("kdesvndelete")), this, SLOT(slotDelete()));
586 tmp_action->setIconText(i18n("Delete"));
587 tmp_action->setToolTip(i18n("Deleting selected files and/or directories from repository"));
588 tmp_action = add_action(QStringLiteral("make_svn_remove_left"), i18n("Delete folder"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvndelete")), this, SLOT(slotLeftDelete()));
589 tmp_action->setToolTip(i18n("Deleting selected directories from repository"));
590 tmp_action->setIconText(i18n("Delete"));
591 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()));
592
593 tmp_action = add_action(QStringLiteral("make_resolved"), i18n("Mark resolved"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnresolved")), this, SLOT(slotResolved()));
594 tmp_action->setToolTip(i18n("Marking files or dirs resolved"));
595
596 tmp_action = add_action(QStringLiteral("make_try_resolve"), i18n("Resolve conflicts"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnresolved")), this, SLOT(slotTryResolve()));
597
598 tmp_action = add_action(QStringLiteral("make_svn_ignore"), i18n("Ignore/Unignore current item"), QKeySequence(), QIcon(), this, SLOT(slotIgnore()));
599 tmp_action = add_action(QStringLiteral("make_left_add_ignore_pattern"), i18n("Add or Remove ignore pattern"), QKeySequence(), QIcon(), this, SLOT(slotLeftRecAddIgnore()));
600 tmp_action = add_action(QStringLiteral("make_right_add_ignore_pattern"), i18n("Add or Remove ignore pattern"), QKeySequence(), QIcon(), this, SLOT(slotRightRecAddIgnore()));
601
602 tmp_action = add_action(QStringLiteral("make_svn_headupdate"), i18n("Update to head"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnupdate")), m_Data->m_Model->svnWrapper(), SLOT(slotUpdateHeadRec()));
603 tmp_action->setIconText(i18nc("Menu item", "Update"));
604 tmp_action = add_action(QStringLiteral("make_svn_revupdate"), i18n("Update to revision..."), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnupdate")), m_Data->m_Model->svnWrapper(), SLOT(slotUpdateTo()));
605 tmp_action = add_action(QStringLiteral("make_svn_commit"), i18n("Commit"), QKeySequence(QStringLiteral("CTRL+#")), QIcon::fromTheme(QStringLiteral("kdesvncommit")), this, SLOT(slotCommit()));
606 tmp_action->setIconText(i18n("Commit"));
607
608 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()));
609 tmp_action->setToolTip(i18n("Diff working copy against BASE (last checked out version) - does not require access to repository"));
610 tmp_action = add_action(QStringLiteral("make_svn_dirbasediff"), i18n("Diff local changes"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvndiff")), this, SLOT(slotDirSimpleBaseDiff()));
611 tmp_action->setToolTip(i18n("Diff working copy against BASE (last checked out version) - does not require access to repository"));
612
613 tmp_action =
614 add_action(QStringLiteral("make_svn_headdiff"), i18n("Diff against HEAD"), QKeySequence(Qt::CTRL | Qt::Key_H), QIcon::fromTheme(QStringLiteral("kdesvndiff")), this, SLOT(slotSimpleHeadDiff()));
615 tmp_action->setToolTip(i18n("Diff working copy against HEAD (last checked in version)- requires access to repository"));
616
617 tmp_action =
618 add_action(QStringLiteral("make_svn_itemsdiff"), i18n("Diff items"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvndiff")), this, SLOT(slotDiffPathes()));
619 tmp_action->setToolTip(i18n("Diff two items"));
620 tmp_action =
621 add_action(QStringLiteral("make_svn_diritemsdiff"), i18n("Diff items"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvndiff")), this, SLOT(slotDiffPathes()));
622 tmp_action->setToolTip(i18n("Diff two items"));
623
624
625 tmp_action =
626 add_action(QStringLiteral("make_svn_merge_revisions"), i18n("Merge two revisions"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnmerge")), this, SLOT(slotMergeRevisions()));
627 tmp_action->setIconText(i18n("Merge"));
628 tmp_action->setToolTip(i18n("Merge two revisions of this entry into itself"));
629
630 tmp_action =
631 add_action(QStringLiteral("make_svn_merge"), i18n("Merge..."), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnmerge")), this, SLOT(slotMerge()));
632 tmp_action->setToolTip(i18n("Merge repository path into current working copy path or current repository path into a target"));
633 tmp_action = add_action(QStringLiteral("openwith"), i18n("Open With..."), QKeySequence(), QIcon(), this, SLOT(slotOpenWith()));
634
635 /* remote actions only */
636 tmp_action =
637 add_action(QStringLiteral("make_svn_checkout_current"), i18n("Checkout current repository path"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncheckout")), m_Data->m_Model->svnWrapper(), SLOT(slotCheckoutCurrent()));
638 tmp_action->setIconText(i18n("Checkout"));
639 tmp_action =
640 add_action(QStringLiteral("make_svn_export_current"), i18n("Export current repository path"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnexport")), m_Data->m_Model->svnWrapper(), SLOT(slotExportCurrent()));
641 add_action(QStringLiteral("switch_browse_revision"), i18n("Select browse revision"), QKeySequence(), QIcon(), this, SLOT(slotSelectBrowsingRevision()));
642
643 /* independe actions */
644 tmp_action =
645 add_action(QStringLiteral("make_svn_checkout"), i18n("Checkout a repository"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncheckout")), m_Data->m_Model->svnWrapper(), SLOT(slotCheckout()));
646 tmp_action->setIconText(i18n("Checkout"));
647 tmp_action = add_action(QStringLiteral("make_svn_export"), i18n("Export a repository"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnexport")), m_Data->m_Model->svnWrapper(), SLOT(slotExport()));
648 tmp_action->setIconText(i18n("Export"));
649 tmp_action = add_action(QStringLiteral("make_view_refresh"), i18n("Refresh view"), QKeySequence(Qt::Key_F5), QIcon::fromTheme(QStringLiteral("kdesvnrightreload")), this, SLOT(refreshCurrentTree()));
650 tmp_action->setIconText(i18n("Refresh"));
651
652 add_action(QStringLiteral("make_revisions_diff"), i18n("Diff revisions"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvndiff")), this, SLOT(slotDiffRevisions()));
653
654 /* folding options */
655 tmp_action = add_action(QStringLiteral("view_unfold_tree"), i18n("Unfold File Tree"), QKeySequence(), QIcon(), this, SLOT(slotUnfoldTree()));
656 tmp_action->setToolTip(i18n("Opens all branches of the file tree"));
657 tmp_action = add_action(QStringLiteral("view_fold_tree"), i18n("Fold File Tree"), QKeySequence(), QIcon(), this , SLOT(slotFoldTree()));
658 tmp_action->setToolTip(i18n("Closes all branches of the file tree"));
659
660 /* caching */
661 tmp_action = add_action(QStringLiteral("update_log_cache"), i18n("Update log cache"), QKeySequence(), QIcon(), this, SLOT(slotUpdateLogCache()));
662 tmp_action->setToolTip(i18n("Update the log cache for current repository"));
663
664 tmp_action = add_action(QStringLiteral("make_dir_commit"), i18n("Commit"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvncommit")), this, SLOT(slotDirCommit()));
665 tmp_action = add_action(QStringLiteral("make_dir_update"), i18n("Update to head"), QKeySequence(), QIcon::fromTheme(QStringLiteral("kdesvnupdate")), this, SLOT(slotDirUpdate()));
666 tmp_action = add_action(QStringLiteral("set_rec_property_dir"), i18n("Set property recursive"), QKeySequence(), QIcon(), this, SLOT(slotDirRecProperty()));
667
668 tmp_action = add_action(QStringLiteral("show_repository_settings"), i18n("Settings for current repository"), QKeySequence(), QIcon(), this, SLOT(slotRepositorySettings()));
669
670 enableActions();
671 }
672
uniqueTypeSelected()673 bool MainTreeWidget::uniqueTypeSelected()
674 {
675 QModelIndexList _mi = m_TreeView->selectionModel()->selectedRows(0);
676 if (_mi.count() < 1) {
677 return false;
678 }
679 bool dir = static_cast<SvnItemModelNode *>(m_Data->srcInd(_mi[0]).internalPointer())->isDir();
680 for (int i = 1; i < _mi.count(); ++i) {
681 if (static_cast<SvnItemModelNode *>(m_Data->srcInd(_mi[i]).internalPointer())->isDir() != dir) {
682 return false;
683 }
684 }
685 return true;
686 }
687
enableAction(const QString & name,bool how)688 void MainTreeWidget::enableAction(const QString &name, bool how)
689 {
690 QAction *temp = filesActions()->action(name);
691 if (temp) {
692 temp->setEnabled(how);
693 temp->setVisible(how);
694 }
695 }
696
enableActions()697 void MainTreeWidget::enableActions()
698 {
699 const bool isopen = !baseUri().isEmpty();
700 const SvnItemList fileList = SelectionList();
701 const SvnItemList dirList = DirSelectionList();
702 const SvnItemModelNode *si = SelectedNode();
703
704 const bool single = isopen && fileList.size() == 1;
705 const bool multi = isopen && fileList.size() > 1;
706 const bool none = isopen && fileList.isEmpty();
707 const bool single_dir = single && si && si->isDir();
708 const bool unique = uniqueTypeSelected();
709 const bool remote_enabled =/*isopen&&*/m_Data->m_Model->svnWrapper()->doNetworking();
710 const bool conflicted = single && si && si->isConflicted();
711
712 bool at_least_one_changed = false;
713 bool at_least_one_conflicted = false;
714 bool at_least_one_local_added = false;
715 bool all_unversioned = true;
716 bool all_versioned = true;
717 bool at_least_one_directory = false;
718 for (auto item : fileList) {
719 if (!item) {
720 // root item
721 continue;
722 }
723 if (item->isChanged()) {
724 at_least_one_changed = true;
725 }
726 if (item->isConflicted()) {
727 at_least_one_conflicted = true;
728 }
729 if (item->isLocalAdded()) {
730 at_least_one_local_added = true;
731 }
732 if (item->isRealVersioned()) {
733 all_unversioned = false;
734 } else {
735 all_versioned = false;
736 }
737 if (item->isDir()) {
738 at_least_one_directory = true;
739 if (item->isChildModified())
740 at_least_one_changed = true;
741 }
742 }
743
744 //qDebug("single: %d, multi: %d, none: %d, single_dir: %d, unique: %d, remove_enabled: %d, conflicted: %d, changed: %d, added: %d",
745 // single, multi, none, single_dir, unique, remote_enabled, conflicted, si && si->isChanged(), si && si->isLocalAdded());
746 //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",
747 // at_least_one_changed, at_least_one_conflicted, at_least_one_local_added, all_unversioned, all_versioned, at_least_one_directory);
748
749 /* local and remote actions */
750 /* 1. actions on dirs AND files */
751 enableAction(QStringLiteral("make_svn_log_nofollow"), single || none);
752 enableAction(QStringLiteral("make_svn_dir_log_nofollow"), dirList.size() == 1 && isopen);
753 enableAction(QStringLiteral("make_last_change"), isopen);
754 enableAction(QStringLiteral("make_svn_log_full"), single || none);
755 enableAction(QStringLiteral("make_svn_tree"), single || none);
756 enableAction(QStringLiteral("make_svn_partialtree"), single || none);
757
758 enableAction(QStringLiteral("make_svn_property"), single);
759 enableAction(QStringLiteral("make_left_svn_property"), dirList.size() == 1);
760 enableAction(QStringLiteral("set_rec_property_dir"), dirList.size() == 1);
761 enableAction(QStringLiteral("get_svn_property"), single);
762 enableAction(QStringLiteral("make_svn_remove"), (multi || single));
763 enableAction(QStringLiteral("make_svn_remove_left"), dirList.size() > 0);
764 enableAction(QStringLiteral("make_svn_lock"), (multi || single));
765 enableAction(QStringLiteral("make_svn_unlock"), (multi || single));
766
767 enableAction(QStringLiteral("make_svn_ignore"), (single) && si && si->parent() != nullptr && !si->isRealVersioned());
768 enableAction(QStringLiteral("make_left_add_ignore_pattern"), (dirList.size() == 1) && isWorkingCopy());
769 enableAction(QStringLiteral("make_right_add_ignore_pattern"), single_dir && isWorkingCopy());
770
771 enableAction(QStringLiteral("make_svn_rename"), single && (!isWorkingCopy() || si != m_Data->m_Model->firstRootChild()));
772 enableAction(QStringLiteral("make_svn_copy"), single && (!isWorkingCopy() || si != m_Data->m_Model->firstRootChild()));
773
774 /* 2. only on files */
775 enableAction(QStringLiteral("make_svn_blame"), single && !single_dir && remote_enabled);
776 enableAction(QStringLiteral("make_svn_range_blame"), single && !single_dir && remote_enabled);
777 enableAction(QStringLiteral("make_svn_cat"), single && !single_dir);
778
779 /* 3. actions only on dirs */
780 enableAction(QStringLiteral("make_svn_mkdir"), single_dir || (none && isopen));
781 enableAction(QStringLiteral("make_svn_switch"), isWorkingCopy() && (single || none));
782 enableAction(QStringLiteral("make_switch_to_repo"), isWorkingCopy());
783 enableAction(QStringLiteral("make_import_dirs_into_current"), single_dir || dirList.size() == 1);
784 enableAction(QStringLiteral("make_svn_relocate"), isWorkingCopy() && (single || none));
785
786 enableAction(QStringLiteral("make_svn_export_current"), ((single && single_dir) || none));
787
788 /* local only actions */
789 /* 1. actions on files AND dirs*/
790 enableAction(QStringLiteral("make_svn_add"), (multi || single) && isWorkingCopy() && all_unversioned);
791 enableAction(QStringLiteral("make_svn_revert"), (multi || single) && isWorkingCopy() && (at_least_one_changed || at_least_one_conflicted || at_least_one_local_added));
792 enableAction(QStringLiteral("make_resolved"), (multi || single) && isWorkingCopy());
793 enableAction(QStringLiteral("make_try_resolve"), conflicted && !single_dir);
794
795 enableAction(QStringLiteral("make_svn_info"), isopen);
796 enableAction(QStringLiteral("make_svn_merge_revisions"), (single || dirList.size() == 1) && isWorkingCopy());
797 enableAction(QStringLiteral("make_svn_merge"), single || dirList.size() == 1 || none);
798 enableAction(QStringLiteral("make_svn_addrec"), (multi || single) && at_least_one_directory && isWorkingCopy() && all_unversioned);
799 enableAction(QStringLiteral("make_svn_headupdate"), isWorkingCopy() && isopen && remote_enabled);
800 enableAction(QStringLiteral("make_dir_update"), isWorkingCopy() && isopen && remote_enabled);
801
802 enableAction(QStringLiteral("make_svn_revupdate"), isWorkingCopy() && isopen && remote_enabled);
803 enableAction(QStringLiteral("make_svn_commit"), isWorkingCopy() && isopen && remote_enabled);
804 enableAction(QStringLiteral("make_dir_commit"), isWorkingCopy() && isopen && remote_enabled);
805
806 enableAction(QStringLiteral("make_svn_basediff"), isWorkingCopy() && (single || none));
807 enableAction(QStringLiteral("make_svn_dirbasediff"), isWorkingCopy() && (dirList.size() < 2));
808 enableAction(QStringLiteral("make_svn_headdiff"), isWorkingCopy() && (single || none) && remote_enabled);
809
810 /// @todo check if all items have same type
811 enableAction(QStringLiteral("make_svn_itemsdiff"), multi && fileList.size() == 2 && unique && remote_enabled && all_versioned);
812 enableAction(QStringLiteral("make_svn_diritemsdiff"), dirList.size() == 2 && isopen && remote_enabled && all_versioned);
813
814 /* 2. on dirs only */
815 enableAction(QStringLiteral("make_cleanup"), isWorkingCopy() && (single_dir || none));
816 enableAction(QStringLiteral("make_check_unversioned"), isWorkingCopy() && ((single_dir && single) || none));
817
818 /* remote actions only */
819 enableAction(QStringLiteral("make_svn_checkout_current"), ((single && single_dir) || none) && !isWorkingCopy() && remote_enabled);
820 /* independ actions */
821 enableAction(QStringLiteral("make_svn_checkout"), remote_enabled);
822 enableAction(QStringLiteral("make_svn_export"), true);
823 enableAction(QStringLiteral("make_view_refresh"), isopen);
824
825 enableAction(QStringLiteral("make_revisions_diff"), isopen);
826 enableAction(QStringLiteral("make_revisions_cat"), isopen && !single_dir && single);
827 enableAction(QStringLiteral("switch_browse_revision"), !isWorkingCopy() && isopen);
828 enableAction(QStringLiteral("make_check_updates"), isWorkingCopy() && isopen && remote_enabled);
829 enableAction(QStringLiteral("openwith"), KAuthorized::authorizeAction("openwith") && single && !single_dir);
830 enableAction(QStringLiteral("show_repository_settings"), isopen);
831
832 enableAction(QStringLiteral("repo_statistic"), isopen);
833
834 QAction *temp = filesActions()->action(QStringLiteral("update_log_cache"));
835 if (temp) {
836 temp->setEnabled(remote_enabled);
837 if (!m_Data->m_Model->svnWrapper()->threadRunning(SvnActions::fillcachethread)) {
838 temp->setText(i18n("Update log cache"));
839 } else {
840 temp->setText(i18n("Stop updating the log cache"));
841 }
842 }
843 }
844
add_action(const QString & actionname,const QString & text,const QKeySequence & sequ,const QIcon & icon,QObject * target,const char * slot)845 QAction *MainTreeWidget::add_action(const QString &actionname,
846 const QString &text,
847 const QKeySequence &sequ,
848 const QIcon &icon,
849 QObject *target,
850 const char *slot)
851 {
852 QAction *tmp_action = nullptr;
853 tmp_action = m_Data->m_Collection->addAction(actionname, target, slot);
854 tmp_action->setText(text);
855 m_Data->m_Collection->setDefaultShortcut(tmp_action, sequ);
856 tmp_action->setIcon(icon);
857 return tmp_action;
858 }
859
filesActions()860 KActionCollection *MainTreeWidget::filesActions()
861 {
862 return m_Data->m_Collection;
863 }
864
closeMe()865 void MainTreeWidget::closeMe()
866 {
867 m_Data->m_Model->svnWrapper()->killallThreads();
868
869 clear();
870 setWorkingCopy(true);
871 setNetworked(false);
872 setWorkingCopy(false);
873 setBaseUri(QString());
874
875 emit changeCaption(QString());
876 emit sigUrlOpened(false);
877 emit sigUrlChanged(QUrl());
878
879 enableActions();
880 m_Data->m_Model->svnWrapper()->reInitClient();
881 }
882
refreshCurrentTree()883 void MainTreeWidget::refreshCurrentTree()
884 {
885 m_Data->m_Model->refreshCurrentTree();
886 if (isWorkingCopy()) {
887 m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
888 }
889 m_Data->m_SortModel->invalidate();
890 setUpdatesEnabled(true);
891 //viewport()->repaint();
892 QTimer::singleShot(1, this, &MainTreeWidget::readSupportData);
893 }
894
slotSettingsChanged()895 void MainTreeWidget::slotSettingsChanged()
896 {
897 m_Data->m_SortModel->setSortCaseSensitivity(Kdesvnsettings::case_sensitive_sort() ? Qt::CaseSensitive : Qt::CaseInsensitive);
898 m_Data->m_SortModel->invalidate();
899 m_Data->m_DirSortModel->invalidate();
900 enableActions();
901 if (m_Data->m_Model->svnWrapper() && !m_Data->m_Model->svnWrapper()->doNetworking()) {
902 m_Data->m_Model->svnWrapper()->stopFillCache();
903 }
904 checkUseNavigation();
905 }
906
offersList(SvnItem * item,bool execOnly) const907 KService::List MainTreeWidget::offersList(SvnItem *item, bool execOnly) const
908 {
909 KService::List offers;
910 if (!item) {
911 return offers;
912 }
913 if (!item->mimeType().isValid()) {
914 return offers;
915 }
916 QString constraint(QLatin1String("(DesktopEntryName != 'kdesvn') and (Type == 'Application')"));
917 if (execOnly) {
918 constraint += QLatin1String(" and (exist Exec)");
919 }
920 offers = KMimeTypeTrader::self()->query(item->mimeType().name(), QString::fromLatin1("Application"), constraint);
921 return offers;
922 }
923
slotItemActivated(const QModelIndex & _index)924 void MainTreeWidget::slotItemActivated(const QModelIndex &_index)
925 {
926 QModelIndex index = m_Data->m_SortModel->mapToSource(_index);
927 itemActivated(index);
928 }
929
itemActivated(const QModelIndex & index,bool keypress)930 void MainTreeWidget::itemActivated(const QModelIndex &index, bool keypress)
931 {
932 Q_UNUSED(keypress);
933 SvnItemModelNode *item;
934 if (index.isValid() && (item = static_cast<SvnItemModelNode *>(index.internalPointer()))) {
935 if (!item->isDir()) {
936 svn::Revision rev;
937 QList<QUrl> lst;
938 lst.append(item->kdeName(rev));
939 KService::List li = offersList(item, true);
940 if (li.isEmpty() || li.first()->exec().isEmpty()) {
941 li = offersList(item);
942 }
943 if (!li.isEmpty() && !li.first()->exec().isEmpty()) {
944 KService::Ptr ptr = li.first();
945 KRun::runService(*ptr, lst, QApplication::activeWindow());
946 } else {
947 KRun::displayOpenWithDialog(lst, QApplication::activeWindow());
948 }
949 } else if (Kdesvnsettings::show_navigation_panel()) {
950 m_DirTreeView->selectionModel()->select(m_Data->m_DirSortModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect);
951 QModelIndex _ind = m_Data->m_Model->parent(index);
952 if (_ind.isValid()) {
953 m_DirTreeView->expand(m_Data->m_DirSortModel->mapFromSource(_ind));
954 }
955 } else {
956
957 }
958 }
959 }
960
slotCheckUpdates()961 void MainTreeWidget::slotCheckUpdates()
962 {
963 if (isWorkingCopy() && m_Data->m_Model->svnWrapper()->doNetworking()) {
964 m_Data->m_TimeUpdates.stop();
965 m_Data->m_Model->svnWrapper()->createUpdateCache(baseUri());
966 }
967 }
968
slotCheckModified()969 void MainTreeWidget::slotCheckModified()
970 {
971 if (isWorkingCopy()) {
972 m_Data->m_TimeModified.stop();
973 m_Data->m_Model->svnWrapper()->createModifiedCache(baseUri());
974 }
975 }
976
slotNotifyMessage(const QString & what)977 void MainTreeWidget::slotNotifyMessage(const QString &what)
978 {
979 emit sigLogMessage(what);
980 QCoreApplication::processEvents();
981 }
982
readSupportData()983 void MainTreeWidget::readSupportData()
984 {
985 /// this moment empty cause no usagedata explicit used by MainTreeWidget
986 }
987
slotClientException(const QString & what)988 void MainTreeWidget::slotClientException(const QString &what)
989 {
990 emit sigLogMessage(what);
991 KMessageBox::sorry(QApplication::activeModalWidget(), what, i18n("SVN Error"));
992 }
993
slotCacheDataChanged()994 void MainTreeWidget::slotCacheDataChanged()
995 {
996 m_Data->m_SortModel->invalidate();
997 if (isWorkingCopy()) {
998 if (!m_Data->m_TimeModified.isActive() && Kdesvnsettings::poll_modified()) {
999 m_Data->m_TimeModified.setInterval(MinutesToMsec(Kdesvnsettings::poll_modified_minutes()));
1000 m_Data->m_TimeModified.start();
1001 }
1002 if (!m_Data->m_TimeUpdates.isActive() && Kdesvnsettings::poll_updates()) {
1003 m_Data->m_TimeUpdates.setInterval(MinutesToMsec(Kdesvnsettings::poll_updates_minutes()));
1004 m_Data->m_TimeUpdates.start();
1005 }
1006 }
1007 }
1008
slotIgnore()1009 void MainTreeWidget::slotIgnore()
1010 {
1011 m_Data->m_Model->makeIgnore(SelectedIndex());
1012 m_Data->m_SortModel->invalidate();
1013 }
1014
slotLeftRecAddIgnore()1015 void MainTreeWidget::slotLeftRecAddIgnore()
1016 {
1017 SvnItem *item = DirSelected();
1018 if (!item || !item->isDir()) {
1019 return;
1020 }
1021 recAddIgnore(item);
1022 }
1023
slotRightRecAddIgnore()1024 void MainTreeWidget::slotRightRecAddIgnore()
1025 {
1026 SvnItem *item = Selected();
1027 if (!item || !item->isDir()) {
1028 return;
1029 }
1030 recAddIgnore(item);
1031 }
1032
recAddIgnore(SvnItem * item)1033 void MainTreeWidget::recAddIgnore(SvnItem *item)
1034 {
1035 QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("ignore_pattern_dlg")));
1036 dlg->setWindowTitle(i18nc("@title:window", "Edit Pattern to Ignore for \"%1\"", item->shortName()));
1037 dlg->setWithCancelButton();
1038 EditIgnorePattern *ptr(new EditIgnorePattern(dlg));
1039 dlg->addWidget(ptr);
1040 if (dlg->exec() != QDialog::Accepted) {
1041 delete dlg;
1042 return;
1043 }
1044 svn::Depth _d = ptr->depth();
1045 QStringList _pattern = ptr->items();
1046 bool unignore = ptr->unignore();
1047 svn::Revision start(svn::Revision::WORKING);
1048 if (!isWorkingCopy()) {
1049 start = baseRevision();
1050 }
1051
1052 svn::StatusEntries res;
1053 if (!m_Data->m_Model->svnWrapper()->makeStatus(item->fullName(), res, start, _d, true /* all entries */, false, false)) {
1054 return;
1055 }
1056 for (int i = 0; i < res.count(); ++i) {
1057 if (!res[i]->isRealVersioned() || res[i]->entry().kind() != svn_node_dir) {
1058 continue;
1059 }
1060 m_Data->m_Model->svnWrapper()->makeIgnoreEntry(res[i]->path(), _pattern, unignore);
1061 }
1062 refreshCurrentTree();
1063 delete dlg;
1064 }
1065
slotMakeLogNoFollow() const1066 void MainTreeWidget::slotMakeLogNoFollow()const
1067 {
1068 doLog(false, false);
1069 }
1070
slotMakeLog() const1071 void MainTreeWidget::slotMakeLog()const
1072 {
1073 doLog(true, false);
1074 }
1075
slotDirMakeLogNoFollow() const1076 void MainTreeWidget::slotDirMakeLogNoFollow()const
1077 {
1078 doLog(false, true);
1079 }
1080
doLog(bool use_follow_settings,bool left) const1081 void MainTreeWidget::doLog(bool use_follow_settings, bool left)const
1082 {
1083 SvnItem *k = left ? DirSelectedOrMain() : SelectedOrMain();
1084 QString what;
1085 if (k) {
1086 what = k->fullName();
1087 } else if (!isWorkingCopy() && selectionCount() == 0) {
1088 what = baseUri();
1089 } else {
1090 return;
1091 }
1092 svn::Revision start(svn::Revision::HEAD);
1093 if (!isWorkingCopy()) {
1094 start = baseRevision();
1095 }
1096 svn::Revision end(svn::Revision::START);
1097 bool list = Kdesvnsettings::self()->log_always_list_changed_files();
1098 bool follow = use_follow_settings ? Kdesvnsettings::log_follows_nodes() : false;
1099 Kdesvnsettings::setLast_node_follow(follow);
1100 int l = 50;
1101 m_Data->m_Model->svnWrapper()->makeLog(start, end, (isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision()), what, follow, list, l);
1102 }
1103
1104
slotContextMenu(const QPoint &)1105 void MainTreeWidget::slotContextMenu(const QPoint &)
1106 {
1107 execContextMenu(SelectionList());
1108 }
1109
slotDirContextMenu(const QPoint & vp)1110 void MainTreeWidget::slotDirContextMenu(const QPoint &vp)
1111 {
1112 QMenu popup;
1113 QAction *temp = nullptr;
1114 int count = 0;
1115 if ((temp = filesActions()->action(QStringLiteral("make_dir_commit"))) && temp->isEnabled() && ++count) {
1116 popup.addAction(temp);
1117 }
1118 if ((temp = filesActions()->action(QStringLiteral("make_dir_update"))) && temp->isEnabled() && ++count) {
1119 popup.addAction(temp);
1120 }
1121 if ((temp = filesActions()->action(QStringLiteral("make_svn_dirbasediff"))) && temp->isEnabled() && ++count) {
1122 popup.addAction(temp);
1123 }
1124 if ((temp = filesActions()->action(QStringLiteral("make_svn_diritemsdiff"))) && temp->isEnabled() && ++count) {
1125 popup.addAction(temp);
1126 }
1127 if ((temp = filesActions()->action(QStringLiteral("make_svn_dir_log_nofollow"))) && temp->isEnabled() && ++count) {
1128 popup.addAction(temp);
1129 }
1130 if ((temp = filesActions()->action(QStringLiteral("make_left_svn_property"))) && temp->isEnabled() && ++count) {
1131 popup.addAction(temp);
1132 }
1133 if ((temp = filesActions()->action(QStringLiteral("make_svn_remove_left"))) && temp->isEnabled() && ++count) {
1134 popup.addAction(temp);
1135 }
1136 if ((temp = filesActions()->action(QStringLiteral("make_left_add_ignore_pattern"))) && temp->isEnabled() && ++count) {
1137 popup.addAction(temp);
1138 }
1139 if ((temp = filesActions()->action(QStringLiteral("set_rec_property_dir"))) && temp->isEnabled() && ++count) {
1140 popup.addAction(temp);
1141 }
1142
1143 OpenContextmenu *me = nullptr;
1144 QAction *menuAction = nullptr;
1145 const SvnItemList l = DirSelectionList();
1146 if (l.count() == 1 && l.at(0)) {
1147 const KService::List offers = offersList(l.at(0), l.at(0)->isDir());
1148 if (!offers.isEmpty()) {
1149 svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1150 me = new OpenContextmenu(l.at(0)->kdeName(rev), offers, nullptr);
1151 me->setTitle(i18n("Open With..."));
1152 menuAction = popup.addMenu(me);
1153 ++count;
1154 }
1155 }
1156 if (count) {
1157 popup.exec(m_DirTreeView->viewport()->mapToGlobal(vp));
1158 }
1159 if (menuAction) {
1160 popup.removeAction(menuAction);
1161 delete menuAction;
1162 }
1163 delete me;
1164
1165 }
1166
execContextMenu(const SvnItemList & l)1167 void MainTreeWidget::execContextMenu(const SvnItemList &l)
1168 {
1169 bool isopen = baseUri().length() > 0;
1170 QString menuname;
1171
1172 if (!isopen) {
1173 menuname = "empty";
1174 } else if (isWorkingCopy()) {
1175 menuname = "local";
1176 } else {
1177 menuname = "remote";
1178 }
1179 if (l.isEmpty()) {
1180 menuname += "_general";
1181 } else if (l.count() > 1) {
1182 menuname += "_context_multi";
1183 } else {
1184 menuname += "_context_single";
1185 if (isWorkingCopy()) {
1186 if (l.at(0)->isRealVersioned()) {
1187 if (l.at(0)->isConflicted()) {
1188 menuname += "_conflicted";
1189 } else {
1190 menuname += "_versioned";
1191 if (l.at(0)->isDir()) {
1192 menuname += "_dir";
1193 }
1194 }
1195 } else {
1196 menuname += "_unversioned";
1197 }
1198 } else if (l.at(0)->isDir()) {
1199 menuname += "_dir";
1200 }
1201 }
1202
1203 //qDebug("menuname: %s", qPrintable(menuname));
1204 QWidget *target;
1205 emit sigShowPopup(menuname, &target);
1206 QMenu *popup = static_cast<QMenu *>(target);
1207 if (!popup) {
1208 return;
1209 }
1210
1211 OpenContextmenu *me = nullptr;
1212 QAction *temp = nullptr;
1213 QAction *menuAction = nullptr;
1214 if (l.count() == 1/*&&!l.at(0)->isDir()*/) {
1215 KService::List offers = offersList(l.at(0), l.at(0)->isDir());
1216 if (!offers.isEmpty()) {
1217 svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1218 me = new OpenContextmenu(l.at(0)->kdeName(rev), offers, nullptr);
1219 me->setTitle(i18n("Open With..."));
1220 menuAction = popup->addMenu(me);
1221 } else {
1222 temp = filesActions()->action(QStringLiteral("openwith"));
1223 if (temp) {
1224 popup->addAction(temp);
1225 }
1226 }
1227 }
1228 popup->exec(QCursor::pos());
1229 if (menuAction) {
1230 popup->removeAction(menuAction);
1231 }
1232 delete me;
1233 if (temp) {
1234 popup->removeAction(temp);
1235 delete temp;
1236 }
1237 }
1238
slotUnfoldTree()1239 void MainTreeWidget::slotUnfoldTree()
1240 {
1241 m_TreeView->expandAll();
1242 }
1243
slotFoldTree()1244 void MainTreeWidget::slotFoldTree()
1245 {
1246 m_TreeView->collapseAll();
1247 }
1248
slotOpenWith()1249 void MainTreeWidget::slotOpenWith()
1250 {
1251 SvnItem *which = Selected();
1252 if (!which || which->isDir()) {
1253 return;
1254 }
1255 svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1256 QList<QUrl> lst;
1257 lst.append(which->kdeName(rev));
1258 KRun::displayOpenWithDialog(lst, QApplication::activeWindow());
1259 }
1260
slotSelectBrowsingRevision()1261 void MainTreeWidget::slotSelectBrowsingRevision()
1262 {
1263 if (isWorkingCopy()) {
1264 return;
1265 }
1266 Rangeinput_impl::revision_range range;
1267 if (Rangeinput_impl::getRevisionRange(range, false)) {
1268 m_Data->m_remoteRevision = range.first;
1269 clear();
1270 m_Data->m_Model->checkDirs(baseUri(), nullptr);
1271 emit changeCaption(baseUri() + QLatin1Char('@') + range.first.toString());
1272 }
1273 }
1274
slotMakeTree()1275 void MainTreeWidget::slotMakeTree()
1276 {
1277 QString what;
1278 SvnItem *k = SelectedOrMain();
1279 if (k) {
1280 what = k->fullName();
1281 } else if (!isWorkingCopy() && selectionCount() == 0) {
1282 what = baseUri();
1283 } else {
1284 return;
1285 }
1286 svn::Revision rev(isWorkingCopy() ? svn::Revision::WORKING : baseRevision());
1287
1288 m_Data->m_Model->svnWrapper()->makeTree(what, rev);
1289 }
1290
slotMakePartTree()1291 void MainTreeWidget::slotMakePartTree()
1292 {
1293 QString what;
1294 SvnItem *k = SelectedOrMain();
1295 if (k) {
1296 what = k->fullName();
1297 } else if (!isWorkingCopy() && selectionCount() == 0) {
1298 what = baseUri();
1299 } else {
1300 return;
1301 }
1302 Rangeinput_impl::revision_range range;
1303 if (Rangeinput_impl::getRevisionRange(range)) {
1304 svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1305 m_Data->m_Model->svnWrapper()->makeTree(what, rev, range.first, range.second);
1306 }
1307 }
1308
slotLock()1309 void MainTreeWidget::slotLock()
1310 {
1311 const SvnItemList lst = SelectionList();
1312 if (lst.isEmpty()) {
1313 KMessageBox::error(this, i18n("Nothing selected for unlock"));
1314 return;
1315 }
1316 QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("locking_log_msg")));
1317 dlg->setWindowTitle(i18nc("@title:window", "Lock Message"));
1318 dlg->setWithCancelButton();
1319 Commitmsg_impl *ptr(new Commitmsg_impl(dlg));
1320 ptr->initHistory();
1321 ptr->hideDepth(true);
1322 ptr->keepsLocks(false);
1323
1324 QCheckBox *_stealLock = new QCheckBox(i18n("Steal lock?"));
1325 ptr->addItemWidget(_stealLock);
1326
1327 dlg->addWidget(ptr);
1328 if (dlg->exec() != QDialog::Accepted) {
1329 if (dlg)
1330 ptr->saveHistory(true);
1331 delete dlg;
1332 return;
1333 }
1334
1335 QString logMessage = ptr->getMessage();
1336 bool steal = _stealLock->isChecked();
1337 ptr->saveHistory(false);
1338
1339 QStringList displist;
1340 for (int i = 0; i < lst.count(); ++i) {
1341 displist.append(lst[i]->fullName());
1342 }
1343 m_Data->m_Model->svnWrapper()->makeLock(displist, logMessage, steal);
1344 refreshCurrentTree();
1345
1346 delete dlg;
1347 }
1348
1349
1350 /*!
1351 \fn MainTreeWidget::slotUnlock()
1352 */
slotUnlock()1353 void MainTreeWidget::slotUnlock()
1354 {
1355 const SvnItemList lst = SelectionList();
1356 if (lst.isEmpty()) {
1357 KMessageBox::error(this, i18n("Nothing selected for unlock"));
1358 return;
1359 }
1360 KMessageBox::ButtonCode res = KMessageBox::questionYesNoCancel(this,
1361 i18n("Break lock or ignore missing locks?"),
1362 i18n("Unlocking items"));
1363 if (res == KMessageBox::Cancel) {
1364 return;
1365 }
1366 bool breakit = res == KMessageBox::Yes;
1367
1368 QStringList displist;
1369 for (int i = 0; i < lst.count(); ++i) {
1370 displist.append(lst[i]->fullName());
1371 }
1372 m_Data->m_Model->svnWrapper()->makeUnlock(displist, breakit);
1373 refreshCurrentTree();
1374 }
1375
slotDisplayLastDiff()1376 void MainTreeWidget::slotDisplayLastDiff()
1377 {
1378 SvnItem *kitem = Selected();
1379 QString what;
1380 if (isWorkingCopy()) {
1381 QDir::setCurrent(baseUri());
1382 }
1383 svn::Revision end = svn::Revision::PREV;
1384 if (!kitem) {
1385 if (isWorkingCopy()) {
1386 kitem = m_Data->m_Model->firstRootChild();
1387 if (!kitem) {
1388 return;
1389 }
1390 what = relativePath(kitem);
1391 } else {
1392 what = baseUri();
1393 }
1394 } else {
1395 what = relativePath(kitem);
1396 }
1397 svn::Revision start;
1398 svn::InfoEntry inf;
1399 if (!kitem) {
1400 // it has to have an item when in working copy, so we know we are in repository view.
1401 if (!m_Data->m_Model->svnWrapper()->singleInfo(what, baseRevision(), inf)) {
1402 return;
1403 }
1404 start = inf.cmtRev();
1405 } else {
1406 start = kitem->cmtRev();
1407 }
1408 if (!isWorkingCopy()) {
1409 if (!m_Data->m_Model->svnWrapper()->singleInfo(what, start.revnum() - 1, inf)) {
1410 return;
1411 }
1412 end = inf.cmtRev();
1413 }
1414 m_Data->m_Model->svnWrapper()->makeDiff(what, end, what, start, realWidget());
1415 }
1416
slotSimpleBaseDiff()1417 void MainTreeWidget::slotSimpleBaseDiff()
1418 {
1419 simpleWcDiff(Selected(), svn::Revision::BASE, svn::Revision::WORKING);
1420 }
1421
slotDirSimpleBaseDiff()1422 void MainTreeWidget::slotDirSimpleBaseDiff()
1423 {
1424 simpleWcDiff(DirSelected(), svn::Revision::BASE, svn::Revision::WORKING);
1425 }
1426
slotSimpleHeadDiff()1427 void MainTreeWidget::slotSimpleHeadDiff()
1428 {
1429 simpleWcDiff(Selected(), svn::Revision::WORKING, svn::Revision::HEAD);
1430 }
1431
simpleWcDiff(SvnItem * kitem,const svn::Revision & first,const svn::Revision & second)1432 void MainTreeWidget::simpleWcDiff(SvnItem *kitem, const svn::Revision &first, const svn::Revision &second)
1433 {
1434 QString what;
1435 if (isWorkingCopy()) {
1436 QDir::setCurrent(baseUri());
1437 }
1438
1439 if (!kitem) {
1440 what = QLatin1Char('.');
1441 } else {
1442 what = relativePath(kitem);
1443 }
1444 // only possible on working copies - so we may say this values
1445 m_Data->m_Model->svnWrapper()->makeDiff(what, first, second, svn::Revision::UNDEFINED, kitem ? kitem->isDir() : true);
1446 }
1447
slotDiffRevisions()1448 void MainTreeWidget::slotDiffRevisions()
1449 {
1450 SvnItem *k = Selected();
1451 QString what;
1452 if (isWorkingCopy()) {
1453 QDir::setCurrent(baseUri());
1454 }
1455
1456 if (!k) {
1457 what = (isWorkingCopy() ? "." : baseUri());
1458 } else {
1459 what = relativePath(k);
1460 }
1461 Rangeinput_impl::revision_range range;
1462 if (Rangeinput_impl::getRevisionRange(range)) {
1463 svn::Revision _peg = (isWorkingCopy() ? svn::Revision::WORKING : baseRevision());
1464 m_Data->m_Model->svnWrapper()->makeDiff(what, range.first, range.second, _peg, k ? k->isDir() : true);
1465 }
1466 }
1467
slotDiffPathes()1468 void MainTreeWidget::slotDiffPathes()
1469 {
1470 SvnItemList lst;
1471
1472 QObject *tr = sender();
1473 bool unique = false;
1474
1475 if (tr == filesActions()->action(QStringLiteral("make_svn_diritemsdiff"))) {
1476 unique = true;
1477 lst = DirSelectionList();
1478 } else {
1479 lst = SelectionList();
1480 }
1481
1482 if (lst.count() != 2 || (!unique && !uniqueTypeSelected())) {
1483 return;
1484 }
1485
1486 SvnItem *k1 = lst.at(0);
1487 SvnItem *k2 = lst.at(1);
1488 QString w1, w2;
1489 svn::Revision r1;
1490
1491 if (isWorkingCopy()) {
1492 QDir::setCurrent(baseUri());
1493 w1 = relativePath(k1);
1494 w2 = relativePath(k2);
1495 r1 = svn::Revision::WORKING;
1496 } else {
1497 w1 = k1->fullName();
1498 w2 = k2->fullName();
1499 r1 = baseRevision();
1500 }
1501 m_Data->m_Model->svnWrapper()->makeDiff(w1, r1, w2, r1);
1502 }
1503
slotInfo()1504 void MainTreeWidget::slotInfo()
1505 {
1506 svn::Revision rev(isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision());
1507 if (!isWorkingCopy()) {
1508 rev = baseRevision();
1509 }
1510 SvnItemList lst = SelectionList();
1511 if (lst.isEmpty()) {
1512 if (!isWorkingCopy()) {
1513 QStringList _sl(baseUri());
1514 m_Data->m_Model->svnWrapper()->makeInfo(_sl, rev, svn::Revision::UNDEFINED, Kdesvnsettings::info_recursive());
1515 } else {
1516 lst.append(SelectedOrMain());
1517 }
1518 }
1519 if (!lst.isEmpty()) {
1520 m_Data->m_Model->svnWrapper()->makeInfo(lst, rev, rev, Kdesvnsettings::info_recursive());
1521 }
1522 }
1523
slotBlame()1524 void MainTreeWidget::slotBlame()
1525 {
1526 SvnItem *k = Selected();
1527 if (!k) {
1528 return;
1529 }
1530 svn::Revision start(svn::Revision::START);
1531 svn::Revision end(svn::Revision::HEAD);
1532 m_Data->m_Model->svnWrapper()->makeBlame(start, end, k);
1533 }
1534
slotRangeBlame()1535 void MainTreeWidget::slotRangeBlame()
1536 {
1537 SvnItem *k = Selected();
1538 if (!k) {
1539 return;
1540 }
1541 Rangeinput_impl::revision_range range;
1542 if (Rangeinput_impl::getRevisionRange(range)) {
1543 m_Data->m_Model->svnWrapper()->makeBlame(range.first, range.second, k);
1544 }
1545 }
1546
_propListTimeout()1547 void MainTreeWidget::_propListTimeout()
1548 {
1549 dispProperties(false);
1550 }
1551
slotDisplayProperties()1552 void MainTreeWidget::slotDisplayProperties()
1553 {
1554 dispProperties(true);
1555 }
1556
refreshItem(SvnItemModelNode * node)1557 void MainTreeWidget::refreshItem(SvnItemModelNode *node)
1558 {
1559 if (node) {
1560 m_Data->m_Model->refreshItem(node);
1561 }
1562 }
1563
slotChangeProperties(const svn::PropertiesMap & pm,const QStringList & dellist,const QString & path)1564 void MainTreeWidget::slotChangeProperties(const svn::PropertiesMap &pm, const QStringList &dellist, const QString &path)
1565 {
1566 m_Data->m_Model->svnWrapper()->changeProperties(pm, dellist, path);
1567 SvnItemModelNode *which = SelectedNode();
1568 if (which && which->fullName() == path) {
1569 m_Data->m_Model->refreshItem(which);
1570 dispProperties(true);
1571 }
1572 }
1573
dispProperties(bool force)1574 void MainTreeWidget::dispProperties(bool force)
1575 {
1576 CursorStack a(Qt::BusyCursor);
1577 bool cache_Only = (!force && isNetworked() && !Kdesvnsettings::properties_on_remote_items());
1578 svn::PathPropertiesMapListPtr pm;
1579 SvnItem *k = Selected();
1580 if (!k || !k->isRealVersioned()) {
1581 emit sigProplist(svn::PathPropertiesMapListPtr(), false, false, QString(""));
1582 return;
1583 }
1584 svn::Revision rev(isWorkingCopy() ? svn::Revision::WORKING : baseRevision());
1585 pm = m_Data->m_Model->svnWrapper()->propList(k->fullName(), rev, cache_Only);
1586 emit sigProplist(pm, isWorkingCopy(), k->isDir(), k->fullName());
1587 }
1588
slotCat()1589 void MainTreeWidget::slotCat()
1590 {
1591 SvnItem *k = Selected();
1592 if (!k) {
1593 return;
1594 }
1595 m_Data->m_Model->svnWrapper()->slotMakeCat(isWorkingCopy() ? svn::Revision::HEAD : baseRevision(), k->fullName(), k->shortName(),
1596 isWorkingCopy() ? svn::Revision::HEAD : baseRevision(), nullptr);
1597 }
1598
slotRevisionCat()1599 void MainTreeWidget::slotRevisionCat()
1600 {
1601 SvnItem *k = Selected();
1602 if (!k) {
1603 return;
1604 }
1605 Rangeinput_impl::revision_range range;
1606 if (Rangeinput_impl::getRevisionRange(range, true, true)) {
1607 m_Data->m_Model->svnWrapper()->slotMakeCat(range.first, k->fullName(), k->shortName(), isWorkingCopy() ? svn::Revision::WORKING : baseRevision(), nullptr);
1608 }
1609 }
1610
slotResolved()1611 void MainTreeWidget::slotResolved()
1612 {
1613 if (!isWorkingCopy()) {
1614 return;
1615 }
1616 SvnItem *which = SelectedOrMain();
1617 if (!which) {
1618 return;
1619 }
1620 m_Data->m_Model->svnWrapper()->slotResolved(which->fullName());
1621 which->refreshStatus(true);
1622 }
1623
slotTryResolve()1624 void MainTreeWidget::slotTryResolve()
1625 {
1626 if (!isWorkingCopy()) {
1627 return;
1628 }
1629 SvnItem *which = Selected();
1630 if (!which || which->isDir()) {
1631 return;
1632 }
1633 m_Data->m_Model->svnWrapper()->slotResolve(which->fullName());
1634 }
1635
slotLeftDelete()1636 void MainTreeWidget::slotLeftDelete()
1637 {
1638 makeDelete(DirSelectionList());
1639 }
1640
slotDelete()1641 void MainTreeWidget::slotDelete()
1642 {
1643 makeDelete(SelectionList());
1644 }
1645
makeDelete(const SvnItemList & lst)1646 void MainTreeWidget::makeDelete(const SvnItemList &lst)
1647 {
1648 if (lst.isEmpty()) {
1649 KMessageBox::error(this, i18n("Nothing selected for delete"));
1650 return;
1651 }
1652 svn::Paths items;
1653 QStringList displist;
1654 QList<QUrl> kioList;
1655 for (const SvnItem *item : lst) {
1656 if (!item->isRealVersioned()) {
1657 QUrl _uri(QUrl::fromLocalFile(item->fullName()));
1658 kioList.append(_uri);
1659 } else {
1660 items.push_back(item->fullName());
1661 }
1662 displist.append(item->fullName());
1663 }
1664
1665 QPointer<DeleteForm> dlg(new DeleteForm(displist, QApplication::activeModalWidget()));
1666 dlg->showExtraButtons(isWorkingCopy() && !items.isEmpty());
1667
1668 if (dlg->exec() == QDialog::Accepted) {
1669 bool force = dlg->force_delete();
1670 bool keep = dlg->keep_local();
1671 WidgetBlockStack st(this);
1672 if (!kioList.isEmpty()) {
1673 KIO::Job *aJob = KIO::del(kioList);
1674 if (!aJob->exec()) {
1675 KJobWidgets::setWindow(aJob, this);
1676 aJob->uiDelegate()->showErrorMessage();
1677 delete dlg;
1678 return;
1679 }
1680 }
1681 if (!items.isEmpty()) {
1682 m_Data->m_Model->svnWrapper()->makeDelete(svn::Targets(items), keep, force);
1683 }
1684 refreshCurrentTree();
1685 }
1686 delete dlg;
1687 }
1688
internalDrop(const QList<QUrl> & _lst,Qt::DropAction action,const QModelIndex & index)1689 void MainTreeWidget::internalDrop(const QList<QUrl> &_lst, Qt::DropAction action, const QModelIndex &index)
1690 {
1691 if (_lst.isEmpty()) {
1692 return;
1693 }
1694 QList<QUrl> lst = _lst;
1695 QString target;
1696 QString nProto;
1697
1698 if (!isWorkingCopy()) {
1699 nProto = svn::Url::transformProtokoll(lst[0].scheme());
1700 }
1701 QList<QUrl>::iterator it = lst.begin();
1702 for (; it != lst.end(); ++it) {
1703 (*it).setQuery(QUrlQuery());
1704 if (!nProto.isEmpty())
1705 (*it).setScheme(nProto);
1706 }
1707
1708 if (index.isValid()) {
1709 SvnItemModelNode *node = static_cast<SvnItemModelNode *>(index.internalPointer());
1710 target = node->fullName();
1711 } else {
1712 target = baseUri();
1713 }
1714 if (action == Qt::MoveAction) {
1715 m_Data->m_Model->svnWrapper()->makeMove(lst, target);
1716 } else if (action == Qt::CopyAction) {
1717 m_Data->m_Model->svnWrapper()->makeCopy(lst, target, (isWorkingCopy() ? svn::Revision::UNDEFINED : baseRevision()));
1718 }
1719 refreshCurrentTree();
1720 }
1721
slotUrlDropped(const QList<QUrl> & _lst,Qt::DropAction action,const QModelIndex & index,bool intern)1722 void MainTreeWidget::slotUrlDropped(const QList<QUrl> &_lst, Qt::DropAction action, const QModelIndex &index, bool intern)
1723 {
1724 if (_lst.isEmpty()) {
1725 return;
1726 }
1727 if (intern) {
1728 internalDrop(_lst, action, index);
1729 return;
1730 }
1731 QUrl target;
1732 if (index.isValid()) {
1733 SvnItemModelNode *node = static_cast<SvnItemModelNode *>(index.internalPointer());
1734 target = node->Url();
1735 } else {
1736 target = baseUriAsUrl();
1737 }
1738
1739 if (baseUri().isEmpty()) {
1740 openUrl(_lst[0]);
1741 return;
1742 }
1743 QString path = _lst[0].path();
1744 QFileInfo fi(path);
1745 if (!isWorkingCopy()) {
1746 if (!fi.isDir()) {
1747 target.setPath(target.path() + QLatin1Char('/') + _lst[0].fileName());
1748 }
1749 slotImportIntoDir(_lst[0].toLocalFile(), target, fi.isDir());
1750 } else {
1751 WidgetBlockStack w(this);
1752 KIO::Job *job = KIO::copy(_lst, target);
1753 connect(job, &KJob::result, this, &MainTreeWidget::slotCopyFinished);
1754 job->exec();
1755 }
1756 }
1757
slotCopyFinished(KJob * _job)1758 void MainTreeWidget::slotCopyFinished(KJob *_job)
1759 {
1760 KIO::CopyJob *job = dynamic_cast<KIO::CopyJob *>(_job);
1761 if (!job) {
1762 return;
1763 }
1764 bool ok = true;
1765 if (job->error()) {
1766 KJobWidgets::setWindow(job, this);
1767 job->uiDelegate()->showErrorMessage();
1768 ok = false;
1769 }
1770 if (ok) {
1771 const QList<QUrl> lst = job->srcUrls();
1772 const QString base = job->destUrl().toLocalFile() + QLatin1Char('/');
1773 svn::Paths tmp;
1774 tmp.reserve(lst.size());
1775 for (const QUrl &url : lst)
1776 tmp.push_back(svn::Path(base + url.fileName()));
1777
1778 m_Data->m_Model->svnWrapper()->addItems(tmp, svn::DepthInfinity);
1779 }
1780 refreshCurrentTree();
1781 }
1782
stopLogCache()1783 void MainTreeWidget::stopLogCache()
1784 {
1785 QAction *temp = filesActions()->action(QStringLiteral("update_log_cache"));
1786 m_Data->m_Model->svnWrapper()->stopFillCache();
1787 if (temp) {
1788 temp->setText(i18n("Update log cache"));
1789 }
1790 }
1791
slotUpdateLogCache()1792 void MainTreeWidget::slotUpdateLogCache()
1793 {
1794 if (baseUri().length() > 0 && m_Data->m_Model->svnWrapper()->doNetworking()) {
1795 QAction *temp = filesActions()->action(QStringLiteral("update_log_cache"));
1796 if (!m_Data->m_Model->svnWrapper()->threadRunning(SvnActions::fillcachethread)) {
1797 m_Data->m_Model->svnWrapper()->startFillCache(baseUri());
1798 if (temp) {
1799 temp->setText(i18n("Stop updating the log cache"));
1800 }
1801 } else {
1802 m_Data->m_Model->svnWrapper()->stopFillCache();
1803 if (temp) {
1804 temp->setText(i18n("Update log cache"));
1805 }
1806 }
1807 }
1808 }
1809
slotMkBaseDirs()1810 void MainTreeWidget::slotMkBaseDirs()
1811 {
1812 bool isopen = !baseUri().isEmpty();
1813 if (!isopen) {
1814 return;
1815 }
1816 QString parentDir = baseUri();
1817 svn::Paths targets;
1818 targets.append(svn::Path(parentDir + QLatin1String("/trunk")));
1819 targets.append(svn::Path(parentDir + QLatin1String("/branches")));
1820 targets.append(svn::Path(parentDir + QLatin1String("/tags")));
1821 QString msg = i18n("Automatic generated base layout by kdesvn");
1822 isopen = m_Data->m_Model->svnWrapper()->makeMkdir(svn::Targets(targets), msg);
1823 if (isopen) {
1824 refreshCurrentTree();
1825 }
1826 }
1827
slotMkdir()1828 void MainTreeWidget::slotMkdir()
1829 {
1830 SvnItemModelNode *k = SelectedNode();
1831 QString parentDir;
1832 if (k) {
1833 if (!k->isDir()) {
1834 KMessageBox::sorry(nullptr, i18n("May not make subdirectories of a file"));
1835 return;
1836 }
1837 parentDir = k->fullName();
1838 } else {
1839 parentDir = baseUri();
1840 }
1841 QString ex = m_Data->m_Model->svnWrapper()->makeMkdir(parentDir);
1842 if (!ex.isEmpty()) {
1843 m_Data->m_Model->refreshDirnode(static_cast<SvnItemModelNodeDir *>(k), true, true);
1844 }
1845 }
1846
slotRename()1847 void MainTreeWidget::slotRename()
1848 {
1849 copy_move(true);
1850 }
slotCopy()1851 void MainTreeWidget::slotCopy()
1852 {
1853 copy_move(false);
1854 }
1855
copy_move(bool move)1856 void MainTreeWidget::copy_move(bool move)
1857 {
1858 if (isWorkingCopy() && SelectedNode() == m_Data->m_Model->firstRootChild()) {
1859 return;
1860 }
1861 bool ok;
1862 SvnItemModelNode *which = SelectedNode();
1863 if (!which) {
1864 return;
1865 }
1866 QString nName = CopyMoveView_impl::getMoveCopyTo(&ok, move, which->fullName(), baseUri(), this);
1867 if (!ok) {
1868 return;
1869 }
1870 if (move) {
1871 m_Data->m_Model->svnWrapper()->makeMove(which->fullName(), nName);
1872 } else {
1873 m_Data->m_Model->svnWrapper()->makeCopy(which->fullName(), nName, isWorkingCopy() ? svn::Revision::HEAD : baseRevision());
1874 }
1875 }
1876
slotCleanupAction()1877 void MainTreeWidget::slotCleanupAction()
1878 {
1879 if (!isWorkingCopy()) {
1880 return;
1881 }
1882 SvnItemModelNode *which = SelectedNode();
1883 if (!which) {
1884 which = m_Data->m_Model->firstRootChild();
1885 }
1886 if (!which || !which->isDir()) {
1887 return;
1888 }
1889 if (m_Data->m_Model->svnWrapper()->makeCleanup(which->fullName())) {
1890 which->refreshStatus(true);
1891 }
1892 }
1893
slotMergeRevisions()1894 void MainTreeWidget::slotMergeRevisions()
1895 {
1896 if (!isWorkingCopy()) {
1897 return;
1898 }
1899 SvnItemModelNode *which = SelectedNode();
1900 if (!which) {
1901 return;
1902 }
1903 bool force, dry, rec, irelated, useExternal, allowmixedrevs;
1904 Rangeinput_impl::revision_range range;
1905 if (!MergeDlg_impl::getMergeRange(range, &force, &rec, &irelated, &dry, &useExternal, &allowmixedrevs, this)) {
1906 return;
1907 }
1908 if (!useExternal) {
1909 m_Data->m_Model->svnWrapper()->slotMergeWcRevisions(which->fullName(), range.first, range.second, rec, !irelated, force, dry, allowmixedrevs);
1910 } else {
1911 m_Data->m_Model->svnWrapper()->slotMergeExternal(which->fullName(), which->fullName(), which->fullName(),
1912 range.first, range.second,
1913 isWorkingCopy() ? svn::Revision::UNDEFINED : m_Data->m_remoteRevision,
1914 rec);
1915 }
1916 refreshItem(which);
1917 if (which->isDir()) {
1918 m_Data->m_Model->refreshDirnode(static_cast<SvnItemModelNodeDir *>(which), true, false);
1919 }
1920 }
1921
slotMerge()1922 void MainTreeWidget::slotMerge()
1923 {
1924 SvnItemModelNode *which = SelectedNode();
1925 QString src1, src2, target;
1926 if (isWorkingCopy()) {
1927 if (m_Data->merge_Target.isEmpty()) {
1928 target = which ? which->fullName() : baseUri();
1929 } else {
1930 target = m_Data->merge_Target;
1931 }
1932 src1 = m_Data->merge_Src1;
1933 } else {
1934 if (m_Data->merge_Src1.isEmpty()) {
1935 src1 = which ? which->fullName() : baseUri();
1936 } else {
1937 src1 = m_Data->merge_Src1;
1938 }
1939 target = m_Data->merge_Target;
1940 }
1941 src2 = m_Data->merge_Src2;
1942 QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("merge_dialog")));
1943 dlg->setWindowTitle(i18nc("@title:window", "Merge"));
1944 dlg->setWithCancelButton();
1945 dlg->setHelp(QLatin1String("merging-items"));
1946 MergeDlg_impl *ptr(new MergeDlg_impl(dlg));
1947 ptr->setDest(target);
1948 ptr->setSrc1(src1);
1949 ptr->setSrc2(src1);
1950 dlg->addWidget(ptr);
1951 if (dlg->exec() == QDialog::Accepted) {
1952 src1 = ptr->Src1();
1953 src2 = ptr->Src2();
1954 if (src2.isEmpty()) {
1955 src2 = src1;
1956 }
1957 target = ptr->Dest();
1958 m_Data->merge_Src2 = src2;
1959 m_Data->merge_Src1 = src1;
1960 m_Data->merge_Target = target;
1961 bool force = ptr->force();
1962 bool dry = ptr->dryrun();
1963 bool rec = ptr->recursive();
1964 bool irelated = ptr->ignorerelated();
1965 bool useExternal = ptr->useExtern();
1966 bool allowmixedrevs = ptr->allowmixedrevs();
1967 bool recordOnly = ptr->recordOnly();
1968 Rangeinput_impl::revision_range range = ptr->getRange();
1969 bool reintegrate = ptr->reintegrate();
1970 if (!useExternal) {
1971 m_Data->m_Model->svnWrapper()->slotMerge(src1, src2, target, range.first, range.second,
1972 isWorkingCopy() ? svn::Revision::UNDEFINED : m_Data->m_remoteRevision,
1973 rec, !irelated, force, dry, recordOnly, reintegrate, allowmixedrevs);
1974 } else {
1975 m_Data->m_Model->svnWrapper()->slotMergeExternal(src1, src2, target, range.first, range.second,
1976 isWorkingCopy() ? svn::Revision::UNDEFINED : m_Data->m_remoteRevision,
1977 rec);
1978 }
1979 if (isWorkingCopy()) {
1980 // refreshItem(which);
1981 // refreshRecursive(which);
1982 refreshCurrentTree();
1983 }
1984 }
1985 delete dlg;
1986 enableActions();
1987 }
1988
slotRelocate()1989 void MainTreeWidget::slotRelocate()
1990 {
1991 if (!isWorkingCopy()) {
1992 return;
1993 }
1994 SvnItem *k = SelectedOrMain();
1995 if (!k) {
1996 KMessageBox::error(nullptr, i18n("Error getting entry to relocate"));
1997 return;
1998 }
1999 const QString path = k->fullName();
2000 const QUrl fromUrl = k->Url();
2001 QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("relocate_dlg")));
2002 dlg->setWindowTitle(i18nc("@title:window", "Relocate Path %1", path));
2003 dlg->setWithCancelButton();
2004 CheckoutInfo_impl *ptr(new CheckoutInfo_impl(dlg));
2005 ptr->setStartUrl(fromUrl);
2006 ptr->disableAppend(true);
2007 ptr->disableTargetDir(true);
2008 ptr->disableRange(true);
2009 ptr->disableOpen(true);
2010 ptr->hideDepth(true);
2011 ptr->hideOverwrite(true);
2012 dlg->addWidget(ptr);
2013 bool done = false;
2014 if (dlg->exec() == QDialog::Accepted) {
2015 if (!ptr->reposURL().isValid()) {
2016 KMessageBox::error(QApplication::activeModalWidget(), i18n("Invalid url given!"),
2017 i18n("Relocate path %1", path));
2018 delete dlg;
2019 return;
2020 }
2021 done = m_Data->m_Model->svnWrapper()->makeRelocate(fromUrl, ptr->reposURL(), path, ptr->overwrite(), ptr->ignoreExternals());
2022 }
2023 delete dlg;
2024 if (done) {
2025 refreshItem(k->sItem());
2026 }
2027 }
2028
slotImportDirsIntoCurrent()2029 void MainTreeWidget::slotImportDirsIntoCurrent()
2030 {
2031 slotImportIntoCurrent(true);
2032 }
2033
2034 /*!
2035 \fn MainTreeWidget::slotImportIntoCurrent()
2036 */
slotImportIntoCurrent(bool dirs)2037 void MainTreeWidget::slotImportIntoCurrent(bool dirs)
2038 {
2039 if (selectionCount() > 1) {
2040 KMessageBox::error(this, i18n("Cannot import into multiple targets"));
2041 return;
2042 }
2043 QUrl targetDir;
2044 if (selectionCount() == 0) {
2045 if (isNetworked())
2046 targetDir = QUrl(baseUri());
2047 else
2048 targetDir = QUrl::fromLocalFile(baseUri());
2049 } else {
2050 targetDir = SelectedNode()->Url();
2051 }
2052 QString source;
2053 if (dirs) {
2054 source = QFileDialog::getExistingDirectory(this, i18n("Import files from folder"));
2055 } else {
2056 source = QFileDialog::getOpenFileName(this, i18n("Import file"), QString());
2057 }
2058
2059 slotImportIntoDir(source, targetDir, dirs);
2060 }
2061
slotImportIntoDir(const QString & source,const QUrl & _targetUri,bool dirs)2062 void MainTreeWidget::slotImportIntoDir(const QString &source, const QUrl &_targetUri, bool dirs)
2063 {
2064 QString sourceUri = source;
2065 while (sourceUri.endsWith(QLatin1Char('/'))) {
2066 sourceUri.chop(1);
2067 }
2068 if (sourceUri.isEmpty()) {
2069 return;
2070 }
2071
2072 if (_targetUri.isEmpty()) {
2073 return;
2074 }
2075 QUrl targetUri(_targetUri);
2076
2077 QPointer<KSvnSimpleOkDialog> dlg(new KSvnSimpleOkDialog(QStringLiteral("import_log_msg")));
2078 dlg->setWindowTitle(i18nc("@title:window", "Import Log"));
2079 dlg->setWithCancelButton();
2080 Commitmsg_impl *ptr = nullptr;
2081 Importdir_logmsg *ptr2 = nullptr;
2082 if (dirs) {
2083 ptr2 = new Importdir_logmsg(dlg);
2084 ptr2->createDirboxDir(QLatin1Char('"') + QFileInfo(sourceUri).fileName() + QLatin1Char('"'));
2085 ptr = ptr2;
2086 } else {
2087 ptr = new Commitmsg_impl(dlg);
2088 }
2089 ptr->initHistory();
2090 dlg->addWidget(ptr);
2091 if (dlg->exec() != QDialog::Accepted) {
2092 if (dlg) {
2093 ptr->saveHistory(true);
2094 delete dlg;
2095 }
2096 return;
2097 }
2098
2099 QString logMessage = ptr->getMessage();
2100 svn::Depth rec = ptr->getDepth();
2101 ptr->saveHistory(false);
2102
2103 if (dirs && ptr2 && ptr2->createDir()) {
2104 targetUri.setPath(targetUri.path() + QLatin1Char('/') + QFileInfo(sourceUri).fileName());
2105 }
2106 if (ptr2) {
2107 m_Data->m_Model->svnWrapper()->slotImport(sourceUri, targetUri, logMessage, rec, ptr2->noIgnore(), ptr2->ignoreUnknownNodes());
2108 } else {
2109 m_Data->m_Model->svnWrapper()->slotImport(sourceUri, targetUri, logMessage, rec, false, false);
2110 }
2111 if (!isWorkingCopy()) {
2112 if (selectionCount() == 0) {
2113 refreshCurrentTree();
2114 } else {
2115 m_Data->m_Model->refreshItem(SelectedNode());
2116 }
2117 }
2118 delete dlg;
2119 }
2120
slotChangeToRepository()2121 void MainTreeWidget::slotChangeToRepository()
2122 {
2123 if (!isWorkingCopy()) {
2124 return;
2125 }
2126 SvnItemModelNode *k = m_Data->m_Model->firstRootChild();
2127 /* huh... */
2128 if (!k) {
2129 return;
2130 }
2131 svn::InfoEntry i;
2132 if (!m_Data->m_Model->svnWrapper()->singleInfo(k->Url().toString(), svn::Revision::UNDEFINED, i)) {
2133 return;
2134 }
2135 if (i.reposRoot().isEmpty()) {
2136 KMessageBox::sorry(QApplication::activeModalWidget(), i18n("Could not retrieve repository of working copy."), i18n("SVN Error"));
2137 } else {
2138 emit sigSwitchUrl(i.reposRoot());
2139 }
2140 }
2141
slotCheckNewItems()2142 void MainTreeWidget::slotCheckNewItems()
2143 {
2144 if (!isWorkingCopy()) {
2145 KMessageBox::sorry(nullptr, i18n("Only in working copy possible."), i18n("Error"));
2146 return;
2147 }
2148 if (selectionCount() > 1) {
2149 KMessageBox::sorry(nullptr, i18n("Only on single folder possible"), i18n("Error"));
2150 return;
2151 }
2152 SvnItem *w = SelectedOrMain();
2153 if (!w) {
2154 KMessageBox::sorry(nullptr, i18n("Sorry - internal error"), i18n("Error"));
2155 return;
2156 }
2157 m_Data->m_Model->svnWrapper()->checkAddItems(w->fullName(), true);
2158 }
2159
refreshCurrent(SvnItem * cur)2160 void MainTreeWidget::refreshCurrent(SvnItem *cur)
2161 {
2162 if (!cur || !cur->sItem()) {
2163 refreshCurrentTree();
2164 return;
2165 }
2166 QCoreApplication::processEvents();
2167 setUpdatesEnabled(false);
2168 if (cur->isDir()) {
2169 m_Data->m_Model->refreshDirnode(static_cast<SvnItemModelNodeDir *>(cur->sItem()));
2170 } else {
2171 m_Data->m_Model->refreshItem(cur->sItem());
2172 }
2173 setUpdatesEnabled(true);
2174 m_TreeView->viewport()->repaint();
2175 }
2176
slotReinitItem(SvnItem * item)2177 void MainTreeWidget::slotReinitItem(SvnItem *item)
2178 {
2179 if (!item) {
2180 return;
2181 }
2182 SvnItemModelNode *k = item->sItem();
2183 if (!k) {
2184 return;
2185 }
2186 m_Data->m_Model->refreshItem(k);
2187 if (k->isDir()) {
2188 m_Data->m_Model->clearNodeDir(static_cast<SvnItemModelNodeDir *>(k));
2189 }
2190 }
2191
keyPressEvent(QKeyEvent * event)2192 void MainTreeWidget::keyPressEvent(QKeyEvent *event)
2193 {
2194 if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !event->isAutoRepeat()) {
2195 QModelIndex index = SelectedIndex();
2196 if (index.isValid()) {
2197 itemActivated(index, true);
2198 return;
2199 }
2200 }
2201 QWidget::keyPressEvent(event);
2202 }
2203
slotItemExpanded(const QModelIndex &)2204 void MainTreeWidget::slotItemExpanded(const QModelIndex &)
2205 {
2206 }
2207
slotItemsInserted(const QModelIndex &)2208 void MainTreeWidget::slotItemsInserted(const QModelIndex &)
2209 {
2210 m_Data->m_resizeColumnsTimer.start(50);
2211 }
2212
slotDirSelectionChanged(const QItemSelection & _item,const QItemSelection &)2213 void MainTreeWidget::slotDirSelectionChanged(const QItemSelection &_item, const QItemSelection &)
2214 {
2215 const QModelIndexList _indexes = _item.indexes();
2216 switch (DirselectionCount()) {
2217 case 1:
2218 m_DirTreeView->setStatusTip(i18n("Hold Ctrl key while click on selected item for unselect"));
2219 break;
2220 case 2:
2221 m_DirTreeView->setStatusTip(i18n("See context menu for more actions"));
2222 break;
2223 case 0:
2224 m_DirTreeView->setStatusTip(i18n("Click for navigate"));
2225 break;
2226 default:
2227 m_DirTreeView->setStatusTip(i18n("Navigation"));
2228 break;
2229 }
2230 if (_indexes.size() >= 1) {
2231 const QModelIndex _t = m_Data->srcDirInd(_indexes.at(0));
2232 if (m_Data->m_Model->canFetchMore(_t)) {
2233 WidgetBlockStack st(m_TreeView);
2234 WidgetBlockStack st2(m_DirTreeView);
2235 m_Data->m_Model->fetchMore(_t);
2236 }
2237 if (Kdesvnsettings::show_navigation_panel()) {
2238 m_TreeView->setRootIndex(m_Data->m_SortModel->mapFromSource(_t));
2239 }
2240 // Display relative path (including name of the checkout) in the titlebar
2241 auto item = m_Data->m_Model->nodeForIndex(_t);
2242 if (item) {
2243 const QString repoBasePath = baseUri();
2244 const QString relativePath = item->fullName().mid(repoBasePath.lastIndexOf('/') + 1);
2245 emit changeCaption(relativePath);
2246 }
2247
2248 } else {
2249 checkSyncTreeModel();
2250 }
2251 if (m_TreeView->selectionModel()->hasSelection()) {
2252 m_TreeView->selectionModel()->clearSelection();
2253 } else {
2254 enableActions();
2255 }
2256 resizeAllColumns();
2257 }
2258
checkSyncTreeModel()2259 void MainTreeWidget::checkSyncTreeModel()
2260 {
2261 // make sure that the treeview shows the contents of the selected directory in the directory tree view
2262 // it can go out of sync when the dir tree model has no current index - then we use the first entry
2263 // or when the filter settings are changed
2264 QModelIndex curIdxDir = m_DirTreeView->currentIndex();
2265 if (!curIdxDir.isValid() && m_Data->m_DirSortModel->columnCount() > 0)
2266 {
2267 m_DirTreeView->setCurrentIndex(m_Data->m_DirSortModel->index(0, 0));
2268 curIdxDir = m_DirTreeView->currentIndex();
2269 }
2270 const QModelIndex curIdxBase = m_Data->srcDirInd(curIdxDir);
2271 m_TreeView->setRootIndex(m_Data->m_SortModel->mapFromSource(curIdxBase));
2272 }
2273
slotCommit()2274 void MainTreeWidget::slotCommit()
2275 {
2276 m_Data->m_Model->svnWrapper()->doCommit(SelectionList());
2277 }
2278
slotDirCommit()2279 void MainTreeWidget::slotDirCommit()
2280 {
2281 m_Data->m_Model->svnWrapper()->doCommit(DirSelectionList());
2282 }
2283
slotDirUpdate()2284 void MainTreeWidget::slotDirUpdate()
2285 {
2286 const SvnItemList which = DirSelectionList();
2287 svn::Paths what;
2288 if (which.isEmpty()) {
2289 what.append(svn::Path(baseUri()));
2290 } else {
2291 what.reserve(which.size());
2292 for (const SvnItem *item : which)
2293 what.append(svn::Path(item->fullName()));
2294 }
2295 m_Data->m_Model->svnWrapper()->makeUpdate(svn::Targets(what), svn::Revision::HEAD, svn::DepthUnknown);
2296 }
2297
slotRefreshItem(const QString & path)2298 void MainTreeWidget::slotRefreshItem(const QString &path)
2299 {
2300 const QModelIndex idx = m_Data->m_Model->findIndex(path);
2301 if (!idx.isValid())
2302 return;
2303 m_Data->m_Model->emitDataChangedRow(idx);
2304 }
2305
checkUseNavigation(bool startup)2306 void MainTreeWidget::checkUseNavigation(bool startup)
2307 {
2308 bool use = Kdesvnsettings::show_navigation_panel();
2309 if (use)
2310 {
2311 checkSyncTreeModel();
2312 }
2313 else
2314 {
2315 // tree view is the only visible view, make sure to display all
2316 m_TreeView->setRootIndex(QModelIndex());
2317 m_TreeView->expand(QModelIndex());
2318 }
2319 m_TreeView->setExpandsOnDoubleClick(!use);
2320 m_TreeView->setRootIsDecorated(!use);
2321 m_TreeView->setItemsExpandable(!use);
2322 QList<int> si;
2323 if (use) {
2324 if (!startup) {
2325 si = m_ViewSplitter->sizes();
2326 if (si.size() == 2 && si[0] < 5) {
2327 si[0] = 200;
2328 m_ViewSplitter->setSizes(si);
2329 }
2330 }
2331 } else {
2332 si << 0 << 300;
2333 m_ViewSplitter->setSizes(si);
2334
2335 }
2336 }
2337
slotRepositorySettings()2338 void MainTreeWidget::slotRepositorySettings()
2339 {
2340 if (baseUri().length() == 0) {
2341 return;
2342 }
2343 svn::InfoEntry inf;
2344 if (!m_Data->m_Model->svnWrapper()->singleInfo(baseUri(), baseRevision(), inf)) {
2345 return;
2346 }
2347 if (inf.reposRoot().isEmpty()) {
2348 KMessageBox::sorry(QApplication::activeModalWidget(), i18n("Could not retrieve repository."), i18n("SVN Error"));
2349 } else {
2350 DbSettings::showSettings(inf.reposRoot().toString(), this);
2351 }
2352 }
2353
slotRightProperties()2354 void MainTreeWidget::slotRightProperties()
2355 {
2356 SvnItem *k = Selected();
2357 if (!k) {
2358 return;
2359 }
2360 m_Data->m_Model->svnWrapper()->editProperties(k, isWorkingCopy() ? svn::Revision::WORKING : svn::Revision::HEAD);
2361 }
2362
slotLeftProperties()2363 void MainTreeWidget::slotLeftProperties()
2364 {
2365 SvnItem *k = DirSelected();
2366 if (!k) {
2367 return;
2368 }
2369 m_Data->m_Model->svnWrapper()->editProperties(k, isWorkingCopy() ? svn::Revision::WORKING : svn::Revision::HEAD);
2370 }
2371
slotDirRecProperty()2372 void MainTreeWidget::slotDirRecProperty()
2373 {
2374 SvnItem *k = DirSelected();
2375 if (!k) {
2376 return;
2377 }
2378 KMessageBox::information(this, i18n("Not yet implemented"), i18n("Edit property recursively"));
2379 }
2380