From: Peter Penz Date: Sun, 12 Jul 2009 14:00:45 +0000 (+0000) Subject: Enable Dolphin to show the revision states of files that are under revision control... X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/fa4680cb38028aceb68d41e1937d27c71d1f121b Enable Dolphin to show the revision states of files that are under revision control systems like SVN, Git, CVS, ... The current code is an early draft and it is planned that all plugins (SVN, Git, CVS, ...) are maintained outside Dolphin. If the API is stable enough, a discussion will be done at kfm-devel@kde.org regarding the location of the plugins (the current implementation of SubversionPlugin is only temporary located in Dolphin for testing purposes). 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 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 83b2eb3d9..38489fceb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/dolphincategorydrawer.cpp b/src/dolphincategorydrawer.cpp index b06f97560..00af90d63 100644 --- a/src/dolphincategorydrawer.cpp +++ b/src/dolphincategorydrawer.cpp @@ -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))); } diff --git a/src/dolphincolumnwidget.cpp b/src/dolphincolumnwidget.cpp index b4c9f11c1..afa79e78f 100644 --- a/src/dolphincolumnwidget.cpp +++ b/src/dolphincolumnwidget.cpp @@ -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() diff --git a/src/dolphindetailsview.cpp b/src/dolphindetailsview.cpp index aa65ff6bc..4a9b9038d 100644 --- a/src/dolphindetailsview.cpp +++ b/src/dolphindetailsview.cpp @@ -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) { diff --git a/src/dolphinfileitemdelegate.cpp b/src/dolphinfileitemdelegate.cpp index 9be70647b..6478baf3b 100644 --- a/src/dolphinfileitemdelegate.cpp +++ b/src/dolphinfileitemdelegate.cpp @@ -19,12 +19,13 @@ #include "dolphinfileitemdelegate.h" +#include +#include + #include #include #include - -#include -#include +#include 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(index.model()); + const DolphinModel* dolphinModel = static_cast(proxyModel->sourceModel()); + if (m_hasMinimizedNameColumn && (index.column() == KDirModel::Name)) { QStyleOptionViewItemV4 opt(option); - const QAbstractProxyModel* proxyModel = static_cast(index.model()); - const KDirModel* dirModel = static_cast(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(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) diff --git a/src/dolphinmodel.cpp b/src/dolphinmodel.cpp index 819b37d2a..f399c3304 100644 --- a/src/dolphinmodel.cpp +++ b/src/dolphinmodel.cpp @@ -45,13 +45,16 @@ #include #include #include +#include #include #include 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(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(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(index.model()); - KFileItem item = dolphinModel->itemForIndex(index); - if (!item.isNull()) { - const Nepomuk::Resource resource(item.url().url(), Soprano::Vocabulary::Xesam::File()); - const QList 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; } diff --git a/src/dolphinmodel.h b/src/dolphinmodel.h index 44067f5a5..b03507dc5 100644 --- a/src/dolphinmodel.h +++ b/src/dolphinmodel.h @@ -22,43 +22,45 @@ #define DOLPHINMODEL_H #include - #include -class LIBDOLPHINPRIVATE_EXPORT DolphinModel - : public KDirModel +#include +#include + +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 m_revisionHash; + static const char* m_others; }; diff --git a/src/dolphinsortfilterproxymodel.cpp b/src/dolphinsortfilterproxymodel.cpp index 2622f9034..d119a416f 100644 --- a/src/dolphinsortfilterproxymodel.cpp +++ b/src/dolphinsortfilterproxymodel.cpp @@ -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(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(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); } diff --git a/src/dolphinview.cpp b/src/dolphinview.cpp index 4a81b12ea..c454d65a5 100644 --- a/src/dolphinview.cpp +++ b/src/dolphinview.cpp @@ -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()), diff --git a/src/panels/folders/paneltreeview.cpp b/src/panels/folders/paneltreeview.cpp index b285789f0..5d3f8a9b8 100644 --- a/src/panels/folders/paneltreeview.cpp +++ b/src/panels/folders/paneltreeview.cpp @@ -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 index 000000000..99fd61b67 --- /dev/null +++ b/src/revisioncontrolobserver.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (C) 2009 by Peter Penz * + * * + * 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 + +#include +#include +#include + +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(view->model()); + m_dolphinModel = (proxyModel == 0) ? + qobject_cast(view->model()) : + qobject_cast(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>&)), + // 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(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 index 000000000..14ea0528e --- /dev/null +++ b/src/revisioncontrolobserver.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2009 by Peter Penz * + * * + * 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 + +#include +#include + +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 index 000000000..6c0f82fb8 --- /dev/null +++ b/src/revisioncontrolplugin.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2009 by Peter Penz * + * * + * 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 + +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 index 000000000..95850711d --- /dev/null +++ b/src/revisioncontrolplugin.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2009 by Peter Penz * + * * + * 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 + +#include + +/** + * @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 +#include + +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 m_fileInfoHash; +}; +#endif // REVISIONCONTROLPLUGIN_H +