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 }