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