File indexing completed on 2024-05-12 17:16:17
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2009 by Rajko Albrecht * 0003 * ral@alwins-world.de * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 0021 #include "svnitem.h" 0022 #include "svnactions.h" 0023 #include "kdesvn_part.h" 0024 #include "settings/kdesvnsettings.h" 0025 #include "svnqt/status.h" 0026 #include "svnqt/url.h" 0027 #include "helpers/ktranslateurl.h" 0028 #include "helpers/kdesvn_debug.h" 0029 0030 #include <klocalizedstring.h> 0031 #include <kiconloader.h> 0032 #include <kiconeffect.h> 0033 #include <kfileitem.h> 0034 0035 #include <QString> 0036 #include <QFileInfo> 0037 #include <QImage> 0038 #include <QMimeDatabase> 0039 #include <QPainter> 0040 #include <QPixmap> 0041 #include <QMutexLocker> 0042 0043 class SvnItem_p 0044 { 0045 public: 0046 SvnItem_p(); 0047 explicit SvnItem_p(const svn::StatusPtr &); 0048 0049 KFileItem &createItem(const svn::Revision &peg); 0050 QUrl &kdeName(const svn::Revision &); 0051 QMimeType mimeType(bool dir); 0052 0053 svn::StatusPtr m_Stat; 0054 void init(); 0055 QUrl m_url; 0056 QString m_full, m_short; 0057 QUrl m_kdename; 0058 QDateTime m_fullDate; 0059 QString m_infoText; 0060 KFileItem m_fitem; 0061 bool isWc; 0062 svn::Revision lRev; 0063 QMimeType m_mimeType; 0064 QMutex _infoTextMutex; 0065 }; 0066 0067 SvnItem_p::SvnItem_p() 0068 : m_Stat(new svn::Status()) 0069 { 0070 init(); 0071 } 0072 0073 SvnItem_p::SvnItem_p(const svn::StatusPtr &aStat) 0074 : m_Stat(aStat) 0075 { 0076 init(); 0077 } 0078 0079 0080 void SvnItem_p::init() 0081 { 0082 isWc = false; 0083 m_full = m_Stat->path(); 0084 m_kdename.clear(); 0085 m_mimeType = QMimeType(); 0086 lRev = svn::Revision::UNDEFINED; 0087 while (m_full.endsWith(QLatin1Char('/'))) { 0088 /* dir name possible */ 0089 m_full.chop(1); 0090 } 0091 int p = m_full.lastIndexOf(QLatin1Char('/')); 0092 if (p > -1) { 0093 ++p; 0094 m_short = m_full.right(m_full.length() - p); 0095 } else { 0096 m_short = m_full; 0097 } 0098 m_url = m_Stat->entry().url(); 0099 m_fullDate = m_Stat->entry().cmtDate().toQDateTime(); 0100 m_infoText.clear(); 0101 } 0102 0103 QMimeType SvnItem_p::mimeType(bool dir) 0104 { 0105 if (!m_mimeType.isValid() || m_kdename.isEmpty()) { 0106 if (m_kdename.isEmpty()) { 0107 kdeName(svn::Revision::UNDEFINED); 0108 } 0109 QMimeDatabase db; 0110 if (dir) { 0111 m_mimeType = db.mimeTypeForName(QLatin1String("inode/directory")); 0112 } else { 0113 m_mimeType = db.mimeTypeForUrl(m_kdename); 0114 } 0115 } 0116 return m_mimeType; 0117 } 0118 0119 QUrl &SvnItem_p::kdeName(const svn::Revision &r) 0120 { 0121 isWc = !svn::Url::isValid(m_Stat->path()); 0122 if (!(r == lRev) || m_kdename.isEmpty()) { 0123 lRev = r; 0124 if (!isWc) { 0125 m_kdename = m_Stat->entry().url(); 0126 QString proto = helpers::KTranslateUrl::makeKdeUrl(m_kdename.scheme()); 0127 m_kdename.setScheme(proto); 0128 QString revstr = lRev.toString(); 0129 if (!revstr.isEmpty()) { 0130 m_kdename.setQuery(QStringLiteral("rev=") + revstr); 0131 } 0132 } else { 0133 // Working copy path() is local file 0134 m_kdename = QUrl::fromLocalFile(m_Stat->path()); 0135 } 0136 } 0137 return m_kdename; 0138 } 0139 0140 KFileItem &SvnItem_p::createItem(const svn::Revision &peg) 0141 { 0142 if (m_fitem.isNull() || !(peg == lRev)) { 0143 m_fitem = KFileItem(kdeName(peg)); 0144 } 0145 return m_fitem; 0146 } 0147 0148 SvnItem::SvnItem() 0149 : m_overlaycolor(false) 0150 , m_bgColor(NONE) 0151 , p_Item(new SvnItem_p()) 0152 { 0153 } 0154 0155 SvnItem::SvnItem(const svn::StatusPtr &aStat) 0156 : m_overlaycolor(false) 0157 , m_bgColor(NONE) 0158 , p_Item(new SvnItem_p(aStat)) 0159 { 0160 } 0161 0162 SvnItem::~SvnItem() 0163 { 0164 } 0165 0166 void SvnItem::setStat(const svn::StatusPtr &aStat) 0167 { 0168 m_overlaycolor = false; 0169 p_Item.reset(new SvnItem_p(aStat)); 0170 SvnActions *wrap = getWrapper(); 0171 if (isChanged() || isConflicted()) { 0172 wrap->addModifiedCache(aStat); 0173 } else { 0174 wrap->deleteFromModifiedCache(fullName()); 0175 } 0176 } 0177 0178 const QString &SvnItem::fullName()const 0179 { 0180 return (p_Item->m_full); 0181 } 0182 0183 const QString &SvnItem::shortName()const 0184 { 0185 return (p_Item->m_short); 0186 } 0187 0188 const QUrl &SvnItem::Url()const 0189 { 0190 return (p_Item->m_url); 0191 } 0192 0193 bool SvnItem::isDir()const 0194 { 0195 if (p_Item->m_Stat->entry().isValid() || isRemoteAdded()) { 0196 if (p_Item->m_Stat->entry().kind() != svn_node_unknown) { 0197 return p_Item->m_Stat->entry().kind() == svn_node_dir; 0198 } 0199 } 0200 /* must be a local file */ 0201 QFileInfo f(fullName()); 0202 return f.isDir(); 0203 } 0204 0205 const QDateTime &SvnItem::fullDate()const 0206 { 0207 return (p_Item->m_fullDate); 0208 } 0209 0210 QPixmap SvnItem::internalTransform(const QPixmap &first, int size) 0211 { 0212 if (first.isNull()) { 0213 return QPixmap(); 0214 } 0215 QPixmap _p = first.scaled(QSize(size, size), Qt::KeepAspectRatio); 0216 if (_p.width() == size && _p.height() == size) { 0217 return _p; 0218 } 0219 QPixmap result(size, size); 0220 result.fill(Qt::transparent); 0221 QPainter pa; 0222 pa.begin(&result); 0223 int w = _p.width() > size ? size : _p.width(); 0224 int h = _p.height() > size ? size : _p.height(); 0225 pa.drawPixmap(0, 0, _p, 0, 0, w, h); 0226 pa.end(); 0227 return result; 0228 } 0229 0230 QPixmap SvnItem::getPixmap(const QPixmap &_p, int size, bool overlay) 0231 { 0232 if (!isVersioned()) { 0233 m_bgColor = NOTVERSIONED; 0234 } else if (isRealVersioned()) { 0235 SvnActions *wrap = getWrapper(); 0236 bool mod = false; 0237 QPixmap p2; 0238 if (p_Item->m_Stat->nodeStatus() == svn_wc_status_conflicted) { 0239 m_bgColor = CONFLICT; 0240 if (overlay) { 0241 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnconflicted"), KIconLoader::Desktop, size); 0242 } 0243 } else if (p_Item->m_Stat->nodeStatus() == svn_wc_status_missing) { 0244 m_bgColor = MISSING; 0245 } else if (isLocked() || (wrap && wrap->checkReposLockCache(fullName()))) { 0246 if (overlay) { 0247 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnlocked"), KIconLoader::Desktop, size); 0248 } 0249 m_bgColor = LOCKED; 0250 } else if (Kdesvnsettings::check_needslock() && !isRemoteAdded() && wrap && wrap->isLockNeeded(this, svn::Revision::UNDEFINED)) { 0251 if (overlay) { 0252 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnneedlock"), KIconLoader::Desktop, size); 0253 } 0254 m_bgColor = NEEDLOCK; 0255 } else if (wrap && wrap->isUpdated(p_Item->m_Stat->path())) { 0256 if (overlay) { 0257 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnupdates"), KIconLoader::Desktop, size); 0258 } 0259 m_bgColor = UPDATES; 0260 } else if (p_Item->m_Stat->nodeStatus() == svn_wc_status_deleted) { 0261 if (overlay) { 0262 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvndeleted"), KIconLoader::Desktop, size); 0263 } 0264 m_bgColor = DELETED; 0265 } else if (p_Item->m_Stat->nodeStatus() == svn_wc_status_added) { 0266 if (overlay) { 0267 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnadded"), KIconLoader::Desktop, size); 0268 } 0269 m_bgColor = ADDED; 0270 } else if (isModified()) { 0271 mod = true; 0272 } else if (isDir() && wrap) { 0273 if (isRemoteAdded() || wrap->checkUpdateCache(fullName())) { 0274 if (overlay) { 0275 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnupdates"), KIconLoader::Desktop, size); 0276 } 0277 m_bgColor = UPDATES; 0278 } else if (wrap->checkConflictedCache(fullName())) { 0279 m_bgColor = CONFLICT; 0280 if (overlay) { 0281 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnconflicted"), KIconLoader::Desktop, size); 0282 } 0283 } else { 0284 mod = wrap->checkModifiedCache(fullName()); 0285 } 0286 } 0287 if (mod) { 0288 m_bgColor = MODIFIED; 0289 if (overlay) { 0290 p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnmodified"), KIconLoader::Desktop, size); 0291 } 0292 } 0293 if (!p2.isNull()) { 0294 QPixmap p; 0295 if (_p.width() != size || _p.height() != size) { 0296 p = internalTransform(_p, size); 0297 } else { 0298 p = _p; 0299 } 0300 if (p2.width() != size || p2.height() != size) { 0301 p2 = internalTransform(p2, size); 0302 } 0303 m_overlaycolor = true; 0304 QImage i1(p.toImage()); 0305 QImage i2(p2.toImage()); 0306 0307 KIconEffect::overlay(i1, i2); 0308 return QPixmap::fromImage(i1); 0309 } 0310 } 0311 return _p; 0312 } 0313 0314 QPixmap SvnItem::getPixmap(int size, bool overlay) 0315 { 0316 QPixmap p; 0317 m_overlaycolor = false; 0318 m_bgColor = NONE; 0319 /* yes - different way to "isDir" above 'cause here we try to use the 0320 mime-features of KDE on ALL not just unversioned entries. 0321 */ 0322 #ifdef DEBUG_TIMER 0323 QTime _counttime; 0324 _counttime.start(); 0325 #endif 0326 if (svn::Url::isValid(p_Item->m_Stat->path())) { 0327 /* remote access */ 0328 p = KIconLoader::global()->loadMimeTypeIcon(p_Item->mimeType(isDir()).iconName(), 0329 KIconLoader::Desktop, 0330 size, 0331 KIconLoader::DefaultState); 0332 if (isLocked()) { 0333 m_bgColor = LOCKED; 0334 if (overlay) { 0335 QPixmap p2 = KIconLoader::global()->loadIcon(QStringLiteral("kdesvnlocked"), KIconLoader::Desktop, size); 0336 if (!p2.isNull()) { 0337 QImage i1; i1 = p.toImage(); 0338 QImage i2; i2 = p2.toImage(); 0339 KIconEffect::overlay(i1, i2); 0340 p.fromImage(i1); 0341 } 0342 } 0343 } 0344 } else { 0345 if (isRemoteAdded()) { 0346 if (isDir()) { 0347 p = KIconLoader::global()->loadIcon(QStringLiteral("folder"), KIconLoader::Desktop, size); 0348 } else { 0349 p = KIconLoader::global()->loadIcon(QStringLiteral("unknown"), KIconLoader::Desktop, size); 0350 } 0351 } else { 0352 // local access 0353 const QUrl uri(QUrl::fromLocalFile(fullName())); 0354 QMimeDatabase db; 0355 const QMimeType mimeType(db.mimeTypeForUrl(uri)); 0356 p = KIconLoader::global()->loadMimeTypeIcon(mimeType.iconName(), KIconLoader::Desktop, size); 0357 p = getPixmap(p, size, overlay); 0358 } 0359 } 0360 #ifdef DEBUG_TIMER 0361 //qCDebug(KDESVN_LOG)<<"Time getting icon: "<<_counttime.elapsed(); 0362 #endif 0363 return p; 0364 } 0365 0366 bool SvnItem::isVersioned()const 0367 { 0368 return p_Item->m_Stat->isVersioned(); 0369 } 0370 0371 bool SvnItem::isValid()const 0372 { 0373 if (isVersioned()) { 0374 return true; 0375 } 0376 QFileInfo f(fullName()); 0377 return f.exists(); 0378 } 0379 0380 bool SvnItem::isRealVersioned()const 0381 { 0382 return p_Item->m_Stat->isRealVersioned(); 0383 } 0384 0385 bool SvnItem::isIgnored()const 0386 { 0387 return p_Item->m_Stat->nodeStatus() == svn_wc_status_ignored; 0388 } 0389 0390 bool SvnItem::isRemoteAdded()const 0391 { 0392 return getWrapper()->isUpdated(p_Item->m_Stat->path()) && 0393 p_Item->m_Stat->validReposStatus() && !p_Item->m_Stat->validLocalStatus(); 0394 } 0395 0396 bool SvnItem::isLocalAdded()const 0397 { 0398 return p_Item->m_Stat->nodeStatus() == svn_wc_status_added; 0399 } 0400 0401 QString SvnItem::infoText()const 0402 { 0403 QString info_text; 0404 if (!isVersioned()) { 0405 info_text = i18n("Not versioned"); 0406 } else if (getWrapper()->isUpdated(p_Item->m_Stat->path())) { 0407 if (p_Item->m_Stat->validReposStatus() && !p_Item->m_Stat->validLocalStatus()) { 0408 info_text = i18n("Added in repository"); 0409 } else { 0410 info_text = i18n("Needs update"); 0411 } 0412 } else { 0413 switch (p_Item->m_Stat->nodeStatus()) { 0414 case svn_wc_status_none: 0415 case svn_wc_status_normal: 0416 break; 0417 case svn_wc_status_unversioned: 0418 info_text = i18n("Not versioned"); 0419 break; 0420 case svn_wc_status_modified: { 0421 if (p_Item->m_Stat->textStatus() == svn_wc_status_modified) 0422 info_text = i18n("Locally modified"); 0423 else 0424 info_text = i18n("Property modified"); 0425 break; 0426 } 0427 case svn_wc_status_added: 0428 info_text = i18n("Locally added"); 0429 break; 0430 case svn_wc_status_missing: 0431 info_text = i18n("Missing"); 0432 break; 0433 case svn_wc_status_deleted: 0434 info_text = i18n("Deleted"); 0435 break; 0436 case svn_wc_status_replaced: 0437 info_text = i18n("Replaced"); 0438 break; 0439 case svn_wc_status_ignored: 0440 info_text = i18n("Ignored"); 0441 break; 0442 case svn_wc_status_external: 0443 info_text = i18n("External"); 0444 break; 0445 case svn_wc_status_conflicted: { 0446 if (p_Item->m_Stat->textStatus() == svn_wc_status_conflicted) 0447 info_text = i18n("Conflict"); 0448 else 0449 info_text = i18n("Property conflicted"); 0450 break; 0451 } 0452 case svn_wc_status_merged: 0453 info_text = i18n("Merged"); 0454 break; 0455 case svn_wc_status_incomplete: 0456 info_text = i18n("Incomplete"); 0457 break; 0458 case svn_wc_status_obstructed: 0459 info_text = i18n("Obstructed"); 0460 break; 0461 } 0462 } 0463 return info_text; 0464 } 0465 0466 QString SvnItem::cmtAuthor()const 0467 { 0468 return p_Item->m_Stat->entry().cmtAuthor(); 0469 } 0470 0471 long int SvnItem::cmtRev()const 0472 { 0473 return p_Item->m_Stat->entry().cmtRev(); 0474 } 0475 0476 bool SvnItem::isLocked()const 0477 { 0478 return p_Item->m_Stat->entry().lockEntry().Locked(); 0479 } 0480 0481 QString SvnItem::lockOwner()const 0482 { 0483 if (p_Item->m_Stat->entry().lockEntry().Locked()) { 0484 return p_Item->m_Stat->entry().lockEntry().Owner(); 0485 } 0486 svn::StatusPtr tmp; 0487 if (getWrapper()->checkReposLockCache(fullName(), tmp) && tmp) { 0488 return tmp->lockEntry().Owner(); 0489 } 0490 return QString(); 0491 } 0492 0493 /*! 0494 \fn SvnItem::isModified() 0495 */ 0496 bool SvnItem::isModified()const 0497 { 0498 return p_Item->m_Stat->nodeStatus() == svn_wc_status_modified 0499 || p_Item->m_Stat->nodeStatus() == svn_wc_status_replaced; 0500 } 0501 0502 bool SvnItem::isChanged()const 0503 { 0504 return isRealVersioned() && (isModified() || isDeleted() || isLocalAdded()); 0505 } 0506 0507 bool SvnItem::isChildModified()const 0508 { 0509 return getWrapper()->checkModifiedCache(fullName()); 0510 } 0511 0512 const svn::StatusPtr &SvnItem::stat()const 0513 { 0514 return p_Item->m_Stat; 0515 } 0516 0517 /*! 0518 \fn SvnItem::isNormal()const 0519 */ 0520 bool SvnItem::isNormal()const 0521 { 0522 return p_Item->m_Stat->nodeStatus() == svn_wc_status_normal; 0523 } 0524 0525 bool SvnItem::isMissing()const 0526 { 0527 return p_Item->m_Stat->nodeStatus() == svn_wc_status_missing; 0528 } 0529 0530 bool SvnItem::isDeleted()const 0531 { 0532 return p_Item->m_Stat->nodeStatus() == svn_wc_status_deleted; 0533 } 0534 0535 bool SvnItem::isConflicted()const 0536 { 0537 return p_Item->m_Stat->nodeStatus() == svn_wc_status_conflicted; 0538 } 0539 0540 bool SvnItem::hasToolTipText() 0541 { 0542 QMutexLocker ml(&(p_Item->_infoTextMutex)); 0543 return !p_Item->m_infoText.isNull(); 0544 } 0545 0546 svn::Revision SvnItem::revision() const 0547 { 0548 if (isRealVersioned() && !p_Item->m_Stat->entry().url().isEmpty()) { 0549 return p_Item->m_Stat->entry().revision(); 0550 } 0551 return svn::Revision::UNDEFINED; 0552 } 0553 0554 /*! 0555 \fn SvnItem::getToolTipText() 0556 */ 0557 const QString &SvnItem::getToolTipText() 0558 { 0559 if (!hasToolTipText()) { 0560 qCDebug(KDESVN_LOG) << "Try getting text" << endl; 0561 QString text; 0562 if (isRealVersioned() && !p_Item->m_Stat->entry().url().isEmpty()) { 0563 SvnActions *wrap = getWrapper(); 0564 svn::Revision peg(svn_opt_revision_unspecified); 0565 svn::Revision rev(svn_opt_revision_unspecified); 0566 if (svn::Url::isValid(p_Item->m_Stat->path())) { 0567 /* remote */ 0568 rev = p_Item->m_Stat->entry().revision(); 0569 peg = correctPeg(); 0570 } else { 0571 /* local */ 0572 } 0573 if (wrap) { 0574 SvnItemList lst; 0575 lst.append(this); 0576 text = wrap->getInfo(lst, rev, peg, false, false); 0577 qCDebug(KDESVN_LOG) << text << endl; 0578 // KF5: TODO 0579 /* 0580 if (!p_Item->m_fitem.isNull()) { 0581 text += p_Item->m_fitem.getToolTipText(0); 0582 } 0583 */ 0584 } 0585 } else if (!p_Item->m_fitem.isNull()) { 0586 // KF5: TODO 0587 // text = p_Item->m_fitem.getToolTipText(6); 0588 } 0589 QMutexLocker ml(&(p_Item->_infoTextMutex)); 0590 p_Item->m_infoText = text; 0591 } 0592 QMutexLocker ml(&(p_Item->_infoTextMutex)); 0593 return p_Item->m_infoText; 0594 } 0595 0596 void SvnItem::generateToolTip(const svn::InfoEntry &entry) 0597 { 0598 QString text; 0599 if (isRealVersioned() && !p_Item->m_Stat->entry().url().isEmpty()) { 0600 SvnActions *wrap = getWrapper(); 0601 if (wrap) { 0602 svn::InfoEntries e; e.append(entry); 0603 text = wrap->getInfo(e, fullName(), false); 0604 } 0605 if (!p_Item->m_fitem.isNull()) { 0606 // KF5: TODO 0607 // text += p_Item->m_fitem.getToolTipText(0); 0608 } 0609 } else if (!p_Item->m_fitem.isNull()) { 0610 // text = p_Item->m_fitem.getToolTipText(6); 0611 } 0612 { 0613 QMutexLocker ml(&(p_Item->_infoTextMutex)); 0614 p_Item->m_infoText = text; 0615 } 0616 } 0617 0618 KFileItem SvnItem::fileItem() 0619 { 0620 return p_Item->createItem(correctPeg()); 0621 } 0622 0623 const QUrl &SvnItem::kdeName(const svn::Revision &r) 0624 { 0625 return p_Item->kdeName(r); 0626 } 0627 0628 QMimeType SvnItem::mimeType() 0629 { 0630 return p_Item->mimeType(isDir()); 0631 }