]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Enable Dolphin to show the revision states of files that are under revision control...
authorPeter Penz <peter.penz19@gmail.com>
Sun, 12 Jul 2009 14:00:45 +0000 (14:00 +0000)
committerPeter Penz <peter.penz19@gmail.com>
Sun, 12 Jul 2009 14:00:45 +0000 (14:00 +0000)
RevisionControlObserver is implemented in a way that no recognizable slowdown is given for directories that are not under revision control.

CCBUG: 192158

svn path=/trunk/KDE/kdebase/apps/; revision=995351

14 files changed:
src/CMakeLists.txt
src/dolphincategorydrawer.cpp
src/dolphincolumnwidget.cpp
src/dolphindetailsview.cpp
src/dolphinfileitemdelegate.cpp
src/dolphinmodel.cpp
src/dolphinmodel.h
src/dolphinsortfilterproxymodel.cpp
src/dolphinview.cpp
src/panels/folders/paneltreeview.cpp
src/revisioncontrolobserver.cpp [new file with mode: 0644]
src/revisioncontrolobserver.h [new file with mode: 0644]
src/revisioncontrolplugin.cpp [new file with mode: 0644]
src/revisioncontrolplugin.h [new file with mode: 0644]

index 83b2eb3d9d9a406ede429ac538c8acc586aa959c..38489fcebd8cbee58b3d7cbaac3f2f8c99fb34c4 100644 (file)
@@ -34,6 +34,8 @@ set(dolphinprivate_LIB_SRCS
     draganddrophelper.cpp
     folderexpander.cpp
     renamedialog.cpp
+    revisioncontrolobserver.cpp
+    revisioncontrolplugin.cpp
     selectiontoggle.cpp
     selectionmanager.cpp
     settings/additionalinfodialog.cpp
index b06f9756085ec8aa0708159d85bbcf8b7b050503..00af90d63e155f75cbdcf4b2a6b7c1f4dd95e0af 100644 (file)
@@ -193,35 +193,18 @@ void DolphinCategoryDrawer::drawCategory(const QModelIndex &index, int sortRole,
             break;
         }
 
-#ifdef HAVE_NEPOMUK
-        case DolphinModel::Rating: {
-            paintText = false;
+        case DolphinModel::Revision:
             paintIcon = false;
-
-            painter->setLayoutDirection( option.direction );
-            QRect ratingRect( option.rect );
-            ratingRect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 2));
-            ratingRect.setHeight( iconSize );
-            KRatingPainter::paintRating( painter, ratingRect, Qt::AlignLeft, category.toInt() );
             break;
-        }
-
-        case DolphinModel::Tags:
-            paintIcon = false;
-            break;
-#endif
     }
 
     if (paintIcon) {
         painter->drawPixmap(QRect(option.direction == Qt::LeftToRight ? opt.rect.left()
                                                                       : opt.rect.right() - icon.width() + (iconSize / 4), opt.rect.top(), icon.width(), icon.height()), icon);
 
-        if (option.direction == Qt::LeftToRight)
-        {
+        if (option.direction == Qt::LeftToRight) {
             opt.rect.setLeft(opt.rect.left() + icon.width() + (iconSize / 4));
-        }
-        else
-        {
+        } else {
             opt.rect.setRight(opt.rect.right() + (iconSize / 4));
         }
     }
@@ -232,9 +215,7 @@ void DolphinCategoryDrawer::drawCategory(const QModelIndex &index, int sortRole,
         painter->setPen(color);
 
         QRect textRect = opt.rect;
-
-        if (option.direction == Qt::RightToLeft)
-        {
+        if (option.direction == Qt::RightToLeft) {
             textRect.setWidth(textRect.width() - (paintIcon ? icon.width() + (iconSize / 4)
                                                             : -(iconSize / 4)));
         }
index b4c9f11c13bade4f0499b9f4b881ba5085b54a7a..afa79e78f2fe3883a0877b315f3a77526136dfa7 100644 (file)
@@ -30,6 +30,7 @@
 #include "dolphin_generalsettings.h"
 #include "draganddrophelper.h"
 #include "folderexpander.h"
+#include "revisioncontrolobserver.h"
 #include "selectionmanager.h"
 #include "tooltips/tooltipmanager.h"
 
@@ -154,6 +155,8 @@ DolphinColumnWidget::DolphinColumnWidget(QWidget* parent,
     folderExpander->setEnabled(DolphinSettings::instance().generalSettings()->autoExpandFolders());
     connect (folderExpander, SIGNAL(enterDir(const QModelIndex&)),
              m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
+
+    new RevisionControlObserver(this);
 }
 
 DolphinColumnWidget::~DolphinColumnWidget()
index aa65ff6bc7fc22e19c072fa07dfbf6d549712be0..4a9b9038d3a4ff9df3d41ca5a196b4cf55cadcb5 100644 (file)
@@ -173,9 +173,6 @@ bool DolphinDetailsView::event(QEvent* event)
         headerView->setMovable(false);
 
         updateColumnVisibility();
-
-        hideColumn(DolphinModel::Rating);
-        hideColumn(DolphinModel::Tags);
     }
 
     return QTreeView::event(event);
@@ -566,7 +563,7 @@ void DolphinDetailsView::configureSettings(const QPoint& pos)
 
     // add checkbox items for each column
     QHeaderView* headerView = header();
-    for (int i = DolphinModel::Size; i <= DolphinModel::Type; ++i) {
+    for (int i = DolphinModel::Size; i <= DolphinModel::Revision; ++i) {
         const int logicalIndex = headerView->logicalIndex(i);
         const QString text = model()->headerData(i, Qt::Horizontal).toString();
         QAction* action = popup.addAction(text);
@@ -601,7 +598,7 @@ void DolphinDetailsView::configureSettings(const QPoint& pos)
 void DolphinDetailsView::updateColumnVisibility()
 {
     const KFileItemDelegate::InformationList list = m_controller->dolphinView()->additionalInfo();
-    for (int i = DolphinModel::Size; i <= DolphinModel::Type; ++i) {
+    for (int i = DolphinModel::Size; i <= DolphinModel::Revision; ++i) {
         const KFileItemDelegate::Information info = infoForColumn(i);
         const bool hide = !list.contains(info);
         if (isColumnHidden(i) != hide) {
@@ -902,13 +899,14 @@ void DolphinDetailsView::resizeColumns()
     QHeaderView* headerView = header();
     QFontMetrics fontMetrics(viewport()->font());
 
-    int columnWidth[KDirModel::ColumnCount];
-    columnWidth[KDirModel::Size] = fontMetrics.width("00000 Items");
-    columnWidth[KDirModel::ModifiedTime] = fontMetrics.width("0000-00-00 00:00");
-    columnWidth[KDirModel::Permissions] = fontMetrics.width("xxxxxxxxxx");
-    columnWidth[KDirModel::Owner] = fontMetrics.width("xxxxxxxxxx");
-    columnWidth[KDirModel::Group] = fontMetrics.width("xxxxxxxxxx");
-    columnWidth[KDirModel::Type] = fontMetrics.width("XXXX Xxxxxxx");
+    int columnWidth[DolphinModel::Revision + 1];
+    columnWidth[DolphinModel::Size] = fontMetrics.width("00000 Items");
+    columnWidth[DolphinModel::ModifiedTime] = fontMetrics.width("0000-00-00 00:00");
+    columnWidth[DolphinModel::Permissions] = fontMetrics.width("xxxxxxxxxx");
+    columnWidth[DolphinModel::Owner] = fontMetrics.width("xxxxxxxxxx");
+    columnWidth[DolphinModel::Group] = fontMetrics.width("xxxxxxxxxx");
+    columnWidth[DolphinModel::Type] = fontMetrics.width("XXXX Xxxxxxx");
+    columnWidth[DolphinModel::Revision] = fontMetrics.width("xxxxxxxx");
 
     int requiredWidth = 0;
     for (int i = KDirModel::Size; i <= KDirModel::Type; ++i) {
index 9be70647b074d62d0ffd915f44f6051d1625ff42..6478baf3ba6d76b3efc160c9b0632db1380056f4 100644 (file)
 
 #include "dolphinfileitemdelegate.h"
 
+#include <dolphinmodel.h>
+#include <kfileitem.h>
+
 #include <QAbstractItemModel>
 #include <QAbstractProxyModel>
 #include <QFontMetrics>
-
-#include <kdirmodel.h>
-#include <kfileitem.h>
+#include <QPainter>
 
 DolphinFileItemDelegate::DolphinFileItemDelegate(QObject* parent) :
     KFileItemDelegate(parent),
@@ -40,17 +41,19 @@ void DolphinFileItemDelegate::paint(QPainter* painter,
                                     const QStyleOptionViewItem& option,
                                     const QModelIndex& index) const
 {
+    const QAbstractProxyModel* proxyModel = static_cast<const QAbstractProxyModel*>(index.model());
+    const DolphinModel* dolphinModel = static_cast<const DolphinModel*>(proxyModel->sourceModel());
+
     if (m_hasMinimizedNameColumn && (index.column() == KDirModel::Name)) {
         QStyleOptionViewItemV4 opt(option);
 
-        const QAbstractProxyModel* proxyModel = static_cast<const QAbstractProxyModel*>(index.model());
-        const KDirModel* dirModel = static_cast<const KDirModel*>(proxyModel->sourceModel());
         const QModelIndex dirIndex = proxyModel->mapToSource(index);
-        const KFileItem item = dirModel->itemForIndex(dirIndex);
+        const KFileItem item = dolphinModel->itemForIndex(dirIndex);
         if (!item.isNull()) {
-            // Symbolic links are displayed in an italic font
-            if (item.isLink())
+            // symbolic links are displayed in an italic font
+            if (item.isLink()) {
                 opt.font.setItalic(true);
+            }
 
             const int width = nameColumnWidth(item.text(), opt);
             opt.rect.setWidth(width);
@@ -59,6 +62,26 @@ void DolphinFileItemDelegate::paint(QPainter* painter,
     } else {
         KFileItemDelegate::paint(painter, option, index);
     }
+
+    if (dolphinModel->hasRevisionData()) {
+        // The currently shown items are under revision control. Show the current revision
+        // state above the decoration.
+        const QModelIndex dirIndex = proxyModel->mapToSource(index);
+        const QModelIndex revisionIndex = dolphinModel->index(dirIndex.row(), DolphinModel::Revision);
+        const QVariant data = dolphinModel->data(revisionIndex, Qt::DecorationRole);
+        const DolphinModel::RevisionState state = static_cast<DolphinModel::RevisionState>(data.toInt());
+
+        if (state != DolphinModel::LocalRevision) {
+            // TODO: The following code is just a proof of concept. Icons will be used later...
+            QColor color(200, 0, 0, 32);
+            switch (state) {
+            case DolphinModel::LatestRevision: color = QColor(0, 180, 0, 32); break;
+            // ...
+            default: break;
+            }
+            painter->fillRect(option.rect, color);
+        }
+    }
 }
 
 int DolphinFileItemDelegate::nameColumnWidth(const QString& name, const QStyleOptionViewItem& option)
index 819b37d2a2a52f28655bd9a1d55fd49023bb14bd..f399c33048476980894e905d8cf5ac39e9b66be3 100644 (file)
 #include <QList>
 #include <QSortFilterProxyModel>
 #include <QPainter>
+#include <QPersistentModelIndex>
 #include <QDir>
 #include <QFileInfo>
 
 const char* DolphinModel::m_others = I18N_NOOP2("@title:group Name", "Others");
 
-DolphinModel::DolphinModel(QObject* parent)
-    : KDirModel(parent)
+DolphinModel::DolphinModel(QObject* parent) :
+    KDirModel(parent),
+    m_hasRevisionData(false),
+    m_revisionHash()
 {
 }
 
@@ -59,72 +62,80 @@ DolphinModel::~DolphinModel()
 {
 }
 
+bool DolphinModel::setData(const QModelIndex& index, const QVariant& value, int role)
+{
+    if ((index.column() == DolphinModel::Revision) && (role == Qt::DecorationRole)) {
+        // TODO: remove data again when items are deleted...
+
+        const QPersistentModelIndex key = index;
+        const RevisionState state = static_cast<RevisionState>(value.toInt());
+        if (m_revisionHash.value(key, LocalRevision) != state) {
+            m_hasRevisionData = true;
+            m_revisionHash.insert(key, state);
+            emit dataChanged(index, index);
+            return true;
+        }
+    }
+
+    return KDirModel::setData(index, value, role);
+}
+
 QVariant DolphinModel::data(const QModelIndex& index, int role) const
 {
     switch (role) {
     case KCategorizedSortFilterProxyModel::CategoryDisplayRole:
         return displayRoleData(index);
+
     case KCategorizedSortFilterProxyModel::CategorySortRole:
         return sortRoleData(index);
+
+    case Qt::DecorationRole:
+        if (index.column() == DolphinModel::Revision) {
+            return m_revisionHash.value(index, LocalRevision);
+        }
+        break;
+
+    case Qt::DisplayRole:
+        if (index.column() == DolphinModel::Revision) {
+            switch (m_revisionHash.value(index, LocalRevision)) {
+            case LatestRevision:
+                return i18nc("@item::intable", "Latest");
+
+            case LocalRevision:
+            default:
+                return i18nc("@item::intable", "Local");
+            }
+        }
+        break;
+
     default:
-        return KDirModel::data(index, role);
+        break;
     }
-}
 
-int DolphinModel::columnCount(const QModelIndex &parent) const
-{
-    return KDirModel::columnCount(parent) + (ExtraColumnCount - ColumnCount);
+    return KDirModel::data(index, role);
 }
 
-quint32 DolphinModel::ratingForIndex(const QModelIndex& index)
+QVariant DolphinModel::headerData(int section, Qt::Orientation orientation, int role) const
 {
-#ifdef HAVE_NEPOMUK
-    quint32 rating = 0;
+    if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) {
+        if (section < KDirModel::ColumnCount) {
+            return KDirModel::headerData(section, orientation, role);
+        }
 
-    const DolphinModel* dolphinModel = static_cast<const DolphinModel*>(index.model());
-    KFileItem item = dolphinModel->itemForIndex(index);
-    if (!item.isNull()) {
-        const Nepomuk::Resource resource(item.url().url(), Soprano::Vocabulary::Xesam::File());
-        rating = resource.rating();
+        Q_ASSERT(section == DolphinModel::Revision);
+        return i18nc("@title::column", "Revision");
     }
-    return rating;
-#else
-    Q_UNUSED(index);
-    return 0;
-#endif
+    return QVariant();
 }
 
-QString DolphinModel::tagsForIndex(const QModelIndex& index)
+int DolphinModel::columnCount(const QModelIndex& parent) const
 {
-#ifdef HAVE_NEPOMUK
-    QString tagsString;
-
-    const DolphinModel* dolphinModel = static_cast<const DolphinModel*>(index.model());
-    KFileItem item = dolphinModel->itemForIndex(index);
-    if (!item.isNull()) {
-        const Nepomuk::Resource resource(item.url().url(), Soprano::Vocabulary::Xesam::File());
-        const QList<Nepomuk::Tag> tags = resource.tags();
-        QStringList stringList;
-        foreach (const Nepomuk::Tag& tag, tags) {
-            stringList.append(tag.label());
-        }
-        stringList.sort();
-
-        foreach (const QString& str, stringList) {
-            tagsString += str;
-            tagsString += ", ";
-        }
-
-        if (!tagsString.isEmpty()) {
-            tagsString.resize(tagsString.size() - 2);
-        }
-    }
+    return KDirModel::columnCount(parent) + (ExtraColumnCount - ColumnCount);
+}
 
-    return tagsString;
-#else
-    Q_UNUSED(index);
-    return QString();
-#endif
+bool DolphinModel::hasRevisionData() const
+{
+    return m_hasRevisionData;
 }
 
 QVariant DolphinModel::displayRoleData(const QModelIndex& index) const
@@ -328,23 +339,11 @@ QVariant DolphinModel::displayRoleData(const QModelIndex& index) const
         retString = item.mimeComment();
         break;
 
-#ifdef HAVE_NEPOMUK
-    case DolphinModel::Rating: {
-        const quint32 rating = ratingForIndex(index);
-        retString = QString::number(rating);
+    case DolphinModel::Revision:
+        retString = "test";
         break;
     }
 
-    case DolphinModel::Tags: {
-        retString = tagsForIndex(index);
-        if (retString.isEmpty()) {
-            retString = i18nc("@title:group Tags", "Not yet tagged");
-        }
-        break;
-    }
-#endif
-    }
-
     return retString;
 }
 
@@ -418,18 +417,6 @@ QVariant DolphinModel::sortRoleData(const QModelIndex& index) const
         }
         break;
 
-#ifdef HAVE_NEPOMUK
-    case DolphinModel::Rating: {
-        retVariant = ratingForIndex(index);
-        break;
-    }
-
-    case DolphinModel::Tags: {
-        retVariant = tagsForIndex(index).count();
-        break;
-    }
-#endif
-
     default:
         break;
     }
index 44067f5a56f3034982b04ce795e4509abc87b861..b03507dc5790471903fb52711edf5308f03830c7 100644 (file)
 #define DOLPHINMODEL_H
 
 #include <kdirmodel.h>
-
 #include <libdolphin_export.h>
 
-class LIBDOLPHINPRIVATE_EXPORT DolphinModel
-    : public KDirModel
+#include <QHash>
+#include <QPersistentModelIndex>
+
+class LIBDOLPHINPRIVATE_EXPORT DolphinModel : public KDirModel
 {
+    Q_OBJECT
+
 public:
     enum AdditionalColumns {
-        Rating = ColumnCount, // ColumnCount defined at KDirModel
-        Tags,
+        Revision = KDirModel::ColumnCount,
         ExtraColumnCount
     };
 
+    enum RevisionState {
+        LocalRevision,
+        LatestRevision
+        // TODO...
+    };
+
     DolphinModel(QObject* parent = 0);
     virtual ~DolphinModel();
 
-    virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-
+    virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
+    virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;    
+    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
     virtual int columnCount(const QModelIndex& parent = QModelIndex()) const;
 
-    /**
-     * Returns the rating for the item with the index \a index. 0 is
-     * returned if no item could be found.
-     */
-    static quint32 ratingForIndex(const QModelIndex& index);
-
-    /**
-     * Returns the tags for the item with the index \a index. If no
-     * tag is applied, a predefined string will be returned.
-     */
-    static QString tagsForIndex(const QModelIndex& index);
+    bool hasRevisionData() const;
 
 private:
     QVariant displayRoleData(const QModelIndex& index) const;
     QVariant sortRoleData(const QModelIndex& index) const;
 
 private:
+    bool m_hasRevisionData;
+    QHash<QPersistentModelIndex, RevisionState> m_revisionHash;
+
     static const char* m_others;
 };
 
index 2622f9034a145d9d67eda77d4e227c2db043172c..d119a416fd0f78870d6e409411fccab319b61077 100644 (file)
@@ -109,50 +109,10 @@ DolphinView::Sorting DolphinSortFilterProxyModel::sortingForColumn(int column)
 bool DolphinSortFilterProxyModel::subSortLessThan(const QModelIndex& left,
                                                   const QModelIndex& right) const
 {
-#ifdef HAVE_NEPOMUK
-    switch (left.column()) {
-    case DolphinView::SortByRating: {
-        const quint32 leftRating  = DolphinModel::ratingForIndex(left);
-        const quint32 rightRating = DolphinModel::ratingForIndex(right);
-
-        if (leftRating == rightRating) {
-            DolphinModel* dolphinModel = static_cast<DolphinModel*>(sourceModel());
-            const KFileItem leftFileItem = dolphinModel->itemForIndex(left);
-            const KFileItem rightFileItem = dolphinModel->itemForIndex(right);
-            bool result;
-            if (isDirectoryOrHidden(leftFileItem, rightFileItem, result)) {
-                return result;
-            }
-
-            return KStringHandler::naturalCompare(leftFileItem.name(), rightFileItem.name(), sortCaseSensitivity()) < 0;
-        }
-
-        return leftRating > rightRating;
-    }
-
-    case DolphinView::SortByTags: {
-        const QString leftTags = DolphinModel::tagsForIndex(left);
-        const QString rightTags = DolphinModel::tagsForIndex(right);
-
-        if (leftTags == rightTags) {
-            DolphinModel* dolphinModel = static_cast<DolphinModel*>(sourceModel());
-            const KFileItem leftFileItem = dolphinModel->itemForIndex(left);
-            const KFileItem rightFileItem = dolphinModel->itemForIndex(right);
-            bool result;
-            if (isDirectoryOrHidden(leftFileItem, rightFileItem, result)) {
-                return result;
-            }
-
-            return KStringHandler::naturalCompare(leftFileItem.name(), rightFileItem.name(), sortCaseSensitivity()) < 0;
-        }
-
-        return KStringHandler::naturalCompare(leftTags, rightTags) < 0;
-    }
-
-    default:
-        break;
-    }
-#endif
+    // switch (left.column()) {
+    // case DolphinView::Revision:
+    //    return left > right;
+    // ...
     return KDirSortFilterProxyModel::subSortLessThan(left, right);
 }
 
index 4a81b12ea949802b804cddf18db3ead37f8ae8d0..c454d65a52f4c7d123eb9080b20a1cce876133ab 100644 (file)
@@ -62,6 +62,7 @@
 #include "draganddrophelper.h"
 #include "folderexpander.h"
 #include "renamedialog.h"
+#include "revisioncontrolobserver.h"
 #include "tooltips/tooltipmanager.h"
 #include "settings/dolphinsettings.h"
 #include "viewproperties.h"
@@ -1460,6 +1461,8 @@ void DolphinView::createView()
     m_previewGenerator = new KFilePreviewGenerator(view);
     m_previewGenerator->setPreviewShown(m_showPreview);
 
+    new RevisionControlObserver(view);
+
     if (DolphinSettings::instance().generalSettings()->showToolTips()) {
         m_toolTipManager = new ToolTipManager(view, m_proxyModel);
         connect(m_controller, SIGNAL(hideToolTip()),
index b285789f08144aef5e94f217f57e934657a9a286..5d3f8a9b8c143d3d4fd231cefc313b4e7753cd2d 100644 (file)
@@ -75,8 +75,7 @@ bool PanelTreeView::event(QEvent* event)
         hideColumn(DolphinModel::Owner);
         hideColumn(DolphinModel::Group);
         hideColumn(DolphinModel::Type);
-        hideColumn(DolphinModel::Rating);
-        hideColumn(DolphinModel::Tags);
+        hideColumn(DolphinModel::Revision);
         header()->hide();
         break;
 
diff --git a/src/revisioncontrolobserver.cpp b/src/revisioncontrolobserver.cpp
new file mode 100644 (file)
index 0000000..99fd61b
--- /dev/null
@@ -0,0 +1,124 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at>                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#include "revisioncontrolobserver.h"
+
+#include "dolphinmodel.h"
+#include "revisioncontrolplugin.h"
+
+#include <kdirlister.h>
+
+#include <QAbstractProxyModel>
+#include <QAbstractItemView>
+#include <QTimer>
+
+RevisionControlObserver::RevisionControlObserver(QAbstractItemView* view) :
+    QObject(view),
+    m_view(view),
+    m_dirLister(0),
+    m_dolphinModel(0),
+    m_dirVerificationTimer(0),
+    m_plugin(0)
+{
+    Q_ASSERT(view != 0);
+
+    QAbstractProxyModel* proxyModel = qobject_cast<QAbstractProxyModel*>(view->model());
+    m_dolphinModel = (proxyModel == 0) ?
+                 qobject_cast<DolphinModel*>(view->model()) :
+                 qobject_cast<DolphinModel*>(proxyModel->sourceModel());
+    if (m_dolphinModel != 0) {
+        m_dirLister = m_dolphinModel->dirLister();
+        connect(m_dirLister, SIGNAL(completed()),
+                this, SLOT(delayedDirectoryVerification()));
+        // TODO:
+        // connect(m_dirLister, SIGNAL(refreshItems(const QList<QPair<KFileItem,KFileItem>>&)),
+        //        this, SLOT(refreshItems()));
+
+        // The verification timer specifies the timeout until the shown directory
+        // is checked whether it is versioned. Per default it is assumed that users
+        // don't iterate through versioned directories and a high timeout is used
+        // The timeout will be decreased as soon as a versioned directory has been
+        // found (see verifyDirectory()).
+        m_dirVerificationTimer = new QTimer(this);
+        m_dirVerificationTimer->setSingleShot(true);
+        m_dirVerificationTimer->setInterval(500);
+        connect(m_dirVerificationTimer, SIGNAL(timeout()),
+                this, SLOT(verifyDirectory()));
+    }
+}
+
+RevisionControlObserver::~RevisionControlObserver()
+{
+    delete m_plugin;
+    m_plugin = 0;
+}
+
+void RevisionControlObserver::delayedDirectoryVerification()
+{
+    m_dirVerificationTimer->start();
+}
+
+void RevisionControlObserver::verifyDirectory()
+{
+    KUrl revisionControlUrl = m_dirLister->url();
+    if (!revisionControlUrl.isLocalFile()) {
+        return;
+    }
+
+    if (m_plugin == 0) {
+        // TODO: just for testing purposes. A plugin approach will be used later.
+        m_plugin = new SubversionPlugin();
+    }
+
+    revisionControlUrl.addPath(m_plugin->fileName());
+    KFileItem item = m_dirLister->findByUrl(revisionControlUrl);
+    if (item.isNull()) {
+        // The directory is not versioned. Reset the verification timer to a higher
+        // value, so that browsing through non-versioned directories is not slown down
+        // by an immediate verification.
+        m_dirVerificationTimer->setInterval(500);
+    } else {
+        // The directory is versioned. Assume that the user will further browse through
+        // versioned directories and decrease the verification timer.
+        m_dirVerificationTimer->setInterval(100);
+        updateItemStates();
+    }
+}
+
+void RevisionControlObserver::updateItemStates()
+{
+    Q_ASSERT(m_plugin != 0);
+    const KUrl directory = m_dirLister->url();
+    if (!m_plugin->beginRetrieval(directory.toLocalFile(KUrl::AddTrailingSlash))) {
+        return;
+    }
+
+    const int rowCount = m_dolphinModel->rowCount();
+    for (int row = 0; row < rowCount; ++row) {
+        const QModelIndex index = m_dolphinModel->index(row, DolphinModel::Revision);
+        const KFileItem item = m_dolphinModel->itemForIndex(index);
+        const RevisionControlPlugin::RevisionState revision = m_plugin->revisionState(item.name());
+        m_dolphinModel->setData(index, QVariant(static_cast<int>(revision)), Qt::DecorationRole);
+    }
+    m_view->viewport()->repaint(); // TODO: this should not be necessary, as DolphinModel::setData() calls dataChanged()
+
+    m_plugin->endRetrieval();
+}
+
+#include "revisioncontrolobserver.moc"
diff --git a/src/revisioncontrolobserver.h b/src/revisioncontrolobserver.h
new file mode 100644 (file)
index 0000000..14ea052
--- /dev/null
@@ -0,0 +1,66 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at>                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#ifndef REVISIONCONTROLOBSERVER_H
+#define REVISIONCONTROLOBSERVER_H
+
+#include <libdolphin_export.h>
+
+#include <QObject>
+#include <QString>
+
+class DolphinModel;
+class KDirLister;
+class QAbstractItemView;
+class QTimer;
+class RevisionControlPlugin;
+
+/**
+ * @brief Observes all revision control plugins.
+ *
+ * The item view gets updated automatically if the currently shown
+ * directory is under revision control.
+ *
+ * @see RevisionControlPlugin
+ */
+class LIBDOLPHINPRIVATE_EXPORT RevisionControlObserver : public QObject
+{
+    Q_OBJECT
+
+public:
+    RevisionControlObserver(QAbstractItemView* view);
+    virtual ~RevisionControlObserver();
+
+private slots:
+    void delayedDirectoryVerification();
+    void verifyDirectory();
+
+private:
+    void updateItemStates();
+
+private:
+    QAbstractItemView* m_view;
+    KDirLister* m_dirLister;
+    DolphinModel* m_dolphinModel;
+    QTimer* m_dirVerificationTimer;
+    RevisionControlPlugin* m_plugin;
+};
+
+#endif // REVISIONCONTROLOBSERVER_H
+
diff --git a/src/revisioncontrolplugin.cpp b/src/revisioncontrolplugin.cpp
new file mode 100644 (file)
index 0000000..6c0f82f
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at>                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#include "revisioncontrolplugin.h"
+
+#include <QDir>
+
+RevisionControlPlugin::RevisionControlPlugin()
+{
+}
+
+RevisionControlPlugin::~RevisionControlPlugin()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+SubversionPlugin::SubversionPlugin() :
+    m_directory(),
+    m_fileInfoHash()
+{
+}
+
+SubversionPlugin::~SubversionPlugin()
+{
+}
+
+QString SubversionPlugin::fileName() const
+{
+    return ".svn";
+}
+
+bool SubversionPlugin::beginRetrieval(const QString& directory)
+{
+    Q_ASSERT(directory.endsWith('/'));
+    const QString path = directory + ".svn/text-base/";
+
+    QDir dir(path);
+    const QFileInfoList fileInfoList = dir.entryInfoList();
+    const int size = fileInfoList.size();
+    QString fileName;
+    for (int i = 0; i < size; ++i) {
+        fileName = fileInfoList.at(i).fileName();
+        // Remove the ".svn-base" postfix to be able to compare the filenames
+        // in a fast way in SubversionPlugin::revisionState().
+        fileName.chop(sizeof(".svn-base") / sizeof(char) - 1);
+        if (!fileName.isEmpty()) {
+            m_fileInfoHash.insert(fileName, fileInfoList.at(i));
+        }
+    }
+    return size > 0;
+}
+
+void SubversionPlugin::endRetrieval()
+{
+}
+
+RevisionControlPlugin::RevisionState SubversionPlugin::revisionState(const QString& fileName)
+{
+    if (m_fileInfoHash.contains(fileName)) {
+        // TODO...
+        return RevisionControlPlugin::LatestRevision;
+    }
+
+    return RevisionControlPlugin::LocalRevision;
+}
diff --git a/src/revisioncontrolplugin.h b/src/revisioncontrolplugin.h
new file mode 100644 (file)
index 0000000..9585071
--- /dev/null
@@ -0,0 +1,103 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Peter Penz <peter.penz@gmx.at>                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#ifndef REVISIONCONTROLPLUGIN_H
+#define REVISIONCONTROLPLUGIN_H
+
+#include <libdolphin_export.h>
+
+#include <QString>
+
+/**
+ * @brief Base class for revision control plugins.
+ *
+ * Enables the file manager to show the revision state
+ * of a revisioned file.
+ */
+class LIBDOLPHINPRIVATE_EXPORT RevisionControlPlugin
+{
+public:
+    enum RevisionState
+    {
+        LocalRevision,
+        LatestRevision
+        // TODO...
+    };
+
+    RevisionControlPlugin();
+    virtual ~RevisionControlPlugin();
+
+    /**
+     * Returns the name of the file which stores
+     * the revision control informations.
+     * (e. g. .svn, .cvs, .git).
+     */
+    virtual QString fileName() const = 0;
+
+    /**
+     * Is invoked whenever the revision control
+     * information will get retrieved for the directory
+     * \p directory. It is assured that the directory
+     * contains a trailing slash.
+     */
+    virtual bool beginRetrieval(const QString& directory) = 0;
+
+    /**
+     * Is invoked after the revision control information has been
+     * received. It is assured that
+     * RevisionControlPlugin::beginInfoRetrieval() has been
+     * invoked before.
+     */
+    virtual void endRetrieval() = 0;
+
+    /**
+     * Returns the revision state for the file with the name \p fileName.
+     * It is assured that RevisionControlPlugin::beginInfoRetrieval() has been
+     * invoked before and that the file is part of the directory specified
+     * in beginInfoRetrieval().
+     */
+    virtual RevisionState revisionState(const QString& fileName) = 0;
+
+};
+
+
+
+
+// TODO: This is just a temporary test class. It will be made available as
+// plugin outside Dolphin later.
+
+#include <QFileInfoList>
+#include <QHash>
+
+class LIBDOLPHINPRIVATE_EXPORT SubversionPlugin : public RevisionControlPlugin
+{
+public:
+    SubversionPlugin();
+    virtual ~SubversionPlugin();
+    virtual QString fileName() const;
+    virtual bool beginRetrieval(const QString& directory);
+    virtual void endRetrieval();
+    virtual RevisionControlPlugin::RevisionState revisionState(const QString& fileName);
+
+private:
+    QString m_directory;
+    QHash<QString, QFileInfo> m_fileInfoHash;
+};
+#endif // REVISIONCONTROLPLUGIN_H
+