diff --git a/src/dolphinfileitemdelegate.cpp b/src/dolphinfileitemdelegate.cpp index 367435cedb..ddd4435a7f 100644 --- a/src/dolphinfileitemdelegate.cpp +++ b/src/dolphinfileitemdelegate.cpp @@ -33,7 +33,9 @@ DolphinFileItemDelegate::DolphinFileItemDelegate(QObject* parent) : KFileItemDelegate(parent), - m_hasMinimizedNameColumn(false) + m_hasMinimizedNameColumn(false), + m_cachedSize(), + m_cachedEmblems() { } @@ -65,12 +67,10 @@ void DolphinFileItemDelegate::paint(QPainter* painter, const QVariant data = dolphinModel->data(revisionIndex, Qt::DecorationRole); const RevisionControlPlugin::RevisionState state = static_cast(data.toInt()); - if (state != RevisionControlPlugin::LocalRevision) { - // TODO: extend KFileItemDelegate to be able to get the icon boundaries - const QRect iconRect(option.rect.x(), option.rect.y(), - KIconLoader::SizeSmall, KIconLoader::SizeSmall); - const QPixmap emblem = emblemForState(state, iconRect.size()); - painter->drawPixmap(iconRect.x(), iconRect.y(), emblem); + if (state != RevisionControlPlugin::UnversionedRevision) { + const QRect rect = iconRect(option, index); + const QPixmap emblem = emblemForState(state, rect.size()); + painter->drawPixmap(rect.x(), rect.y() + rect.height() - emblem.height(), emblem); } } } @@ -105,23 +105,42 @@ void DolphinFileItemDelegate::adjustOptionWidth(QStyleOptionViewItemV4& option, } } -QPixmap DolphinFileItemDelegate::emblemForState(RevisionControlPlugin::RevisionState state, const QSize& size) +QPixmap DolphinFileItemDelegate::emblemForState(RevisionControlPlugin::RevisionState state, const QSize& size) const { - // TODO #1: all icons that are use here will be replaced by revision control emblems provided by the + // TODO: all icons that are use here will be replaced by revision control emblems provided by the // Oxygen team before KDE 4.4 - // TODO #2: cache the icons - switch (state) { - case RevisionControlPlugin::LatestRevision: - return KIcon("dialog-ok-apply").pixmap(size); - case RevisionControlPlugin::ConflictingRevision: - return KIcon("application-exit").pixmap(size); - case RevisionControlPlugin::UpdateRequiredRevision: - return KIcon("rating").pixmap(size); - case RevisionControlPlugin::EditingRevision: - return KIcon("emblem-important").pixmap(size); - default: - break; + Q_ASSERT(state <= RevisionControlPlugin::ConflictingRevision); + if ((m_cachedSize != size) || !m_cachedEmblems[state].isNull()) { + m_cachedSize = size; + + const int iconHeight = size.height(); + int emblemHeight = KIconLoader::SizeSmall; + if (iconHeight >= KIconLoader::SizeEnormous) { + emblemHeight = KIconLoader::SizeMedium; + } else if (iconHeight >= KIconLoader::SizeLarge) { + emblemHeight = KIconLoader::SizeSmallMedium; + } else if (iconHeight >= KIconLoader::SizeMedium) { + emblemHeight = KIconLoader::SizeSmall; + } else { + // TODO: it depends on the final icons whether a smaller size works + emblemHeight = KIconLoader::SizeSmall /* / 2 */; + } + + const QSize emblemSize(emblemHeight, emblemHeight); + for (int i = 0; i <= RevisionControlPlugin::ConflictingRevision; ++i) { + QString iconName; + switch (state) { + case RevisionControlPlugin::NormalRevision: iconName = "dialog-ok-apply"; break; + case RevisionControlPlugin::UpdateRequiredRevision: iconName = "rating"; break; + case RevisionControlPlugin::LocallyModifiedRevision: iconName = "emblem-important"; break; + case RevisionControlPlugin::AddedRevision: iconName = "list-add"; break; + case RevisionControlPlugin::ConflictingRevision: iconName = "application-exit"; break; + default: Q_ASSERT(false); break; + } + + m_cachedEmblems[i] = KIcon(iconName).pixmap(emblemSize); + } } - return QPixmap(); + return m_cachedEmblems[state]; } diff --git a/src/dolphinfileitemdelegate.h b/src/dolphinfileitemdelegate.h index 2f8d3c35f9..bd6bfdf073 100644 --- a/src/dolphinfileitemdelegate.h +++ b/src/dolphinfileitemdelegate.h @@ -66,10 +66,12 @@ private: const DolphinModel* dolphinModel, const QModelIndex& index); - static QPixmap emblemForState(RevisionControlPlugin::RevisionState state, const QSize& size); + QPixmap emblemForState(RevisionControlPlugin::RevisionState state, const QSize& size) const; private: bool m_hasMinimizedNameColumn; + mutable QSize m_cachedSize; + mutable QPixmap m_cachedEmblems[RevisionControlPlugin::ConflictingRevision + 1]; }; inline void DolphinFileItemDelegate::setMinimizedNameColumn(bool minimized) diff --git a/src/dolphinmodel.cpp b/src/dolphinmodel.cpp index 542d550ae3..207b5a40fd 100644 --- a/src/dolphinmodel.cpp +++ b/src/dolphinmodel.cpp @@ -69,7 +69,7 @@ bool DolphinModel::setData(const QModelIndex& index, const QVariant& value, int const QPersistentModelIndex key = index; const RevisionControlPlugin::RevisionState state = static_cast(value.toInt()); - if (m_revisionHash.value(key, RevisionControlPlugin::LocalRevision) != state) { + if (m_revisionHash.value(key, RevisionControlPlugin::UnversionedRevision) != state) { if (!m_hasRevisionData) { connect(this, SIGNAL(rowsRemoved (const QModelIndex&, int, int)), this, SLOT(slotRowsRemoved(const QModelIndex&, int, int))); @@ -96,22 +96,22 @@ QVariant DolphinModel::data(const QModelIndex& index, int role) const case Qt::DecorationRole: if (index.column() == DolphinModel::Revision) { - return m_revisionHash.value(index, RevisionControlPlugin::LocalRevision); + return m_revisionHash.value(index, RevisionControlPlugin::UnversionedRevision); } break; case Qt::DisplayRole: if (index.column() == DolphinModel::Revision) { - switch (m_revisionHash.value(index, RevisionControlPlugin::LocalRevision)) { - case RevisionControlPlugin::LatestRevision: - return i18nc("@item::intable", "Latest"); - case RevisionControlPlugin::EditingRevision: - return i18nc("@item::intable", "Editing"); + switch (m_revisionHash.value(index, RevisionControlPlugin::UnversionedRevision)) { + case RevisionControlPlugin::NormalRevision: + return i18nc("@item::intable", "Normal"); + case RevisionControlPlugin::LocallyModifiedRevision: + return i18nc("@item::intable", "Locally modified"); case RevisionControlPlugin::UpdateRequiredRevision: return i18nc("@item::intable", "Update required"); - case RevisionControlPlugin::LocalRevision: + case RevisionControlPlugin::UnversionedRevision: default: - return i18nc("@item::intable", "Local"); + return i18nc("@item::intable", "Unversioned"); } } break; @@ -141,6 +141,12 @@ int DolphinModel::columnCount(const QModelIndex& parent) const return KDirModel::columnCount(parent) + (ExtraColumnCount - ColumnCount); } +void DolphinModel::clearRevisionData() +{ + m_revisionHash.clear(); + m_hasRevisionData = false; +} + bool DolphinModel::hasRevisionData() const { return m_hasRevisionData; @@ -148,11 +154,11 @@ bool DolphinModel::hasRevisionData() const void DolphinModel::slotRowsRemoved(const QModelIndex& parent, int start, int end) { - Q_ASSERT(hasRevisionData()); - - const int column = parent.column(); - for (int row = start; row <= end; ++row) { - m_revisionHash.remove(parent.child(row, column)); + if (m_hasRevisionData) { + const int column = parent.column(); + for (int row = start; row <= end; ++row) { + m_revisionHash.remove(parent.child(row, column)); + } } } diff --git a/src/dolphinmodel.h b/src/dolphinmodel.h index 9ae3d5f7c9..1fd96c5f6e 100644 --- a/src/dolphinmodel.h +++ b/src/dolphinmodel.h @@ -46,6 +46,7 @@ public: virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; + void clearRevisionData(); bool hasRevisionData() const; private slots: diff --git a/src/dolphinview.cpp b/src/dolphinview.cpp index a12e7a991a..2fc664f214 100644 --- a/src/dolphinview.cpp +++ b/src/dolphinview.cpp @@ -522,6 +522,10 @@ void DolphinView::updateView(const KUrl& url, const KUrl& rootUrl) loadDirectory(url); } + // When changing the URL there is no need to keep the revision + // data of the previous URL. + m_dolphinModel->clearRevisionData(); + emit startedPathLoading(url); } diff --git a/src/revisioncontrolobserver.cpp b/src/revisioncontrolobserver.cpp index f3bf08ce42..1e7347a9bf 100644 --- a/src/revisioncontrolobserver.cpp +++ b/src/revisioncontrolobserver.cpp @@ -26,6 +26,7 @@ #include #include +#include #include /** @@ -36,7 +37,7 @@ class UpdateItemStatesThread : public QThread { public: - UpdateItemStatesThread(QObject* parent); + UpdateItemStatesThread(QObject* parent, QMutex* pluginMutex); void setData(RevisionControlPlugin* plugin, const QList& itemStates); QList itemStates() const; @@ -46,11 +47,13 @@ protected: private: RevisionControlPlugin* m_plugin; + QMutex* m_pluginMutex; QList m_itemStates; }; -UpdateItemStatesThread::UpdateItemStatesThread(QObject* parent) : - QThread(parent) +UpdateItemStatesThread::UpdateItemStatesThread(QObject* parent, QMutex* pluginMutex) : + QThread(parent), + m_pluginMutex(pluginMutex) { } @@ -68,7 +71,8 @@ void UpdateItemStatesThread::run() // it is assumed that all items have the same parent directory const QString directory = m_itemStates.first().item.url().directory(KUrl::AppendTrailingSlash); - + + QMutexLocker locker(m_pluginMutex); if (m_plugin->beginRetrieval(directory)) { const int count = m_itemStates.count(); for (int i = 0; i < count; ++i) { @@ -83,7 +87,7 @@ QList UpdateItemStatesThread::itemStates() c return m_itemStates; } -// --- +// ------------------------------------------------------------------------------------------------ RevisionControlObserver::RevisionControlObserver(QAbstractItemView* view) : QObject(view), @@ -93,6 +97,7 @@ RevisionControlObserver::RevisionControlObserver(QAbstractItemView* view) : m_dirLister(0), m_dolphinModel(0), m_dirVerificationTimer(0), + m_pluginMutex(QMutex::Recursive), m_plugin(0), m_updateItemStatesThread(0) { @@ -100,8 +105,8 @@ RevisionControlObserver::RevisionControlObserver(QAbstractItemView* view) : QAbstractProxyModel* proxyModel = qobject_cast(view->model()); m_dolphinModel = (proxyModel == 0) ? - qobject_cast(view->model()) : - qobject_cast(proxyModel->sourceModel()); + qobject_cast(view->model()) : + qobject_cast(proxyModel->sourceModel()); if (m_dolphinModel != 0) { m_dirLister = m_dolphinModel->dirLister(); connect(m_dirLister, SIGNAL(completed()), @@ -129,6 +134,7 @@ RevisionControlObserver::~RevisionControlObserver() QList RevisionControlObserver::contextMenuActions(const KFileItemList& items) const { if (m_dolphinModel->hasRevisionData() && (m_plugin != 0)) { + QMutexLocker locker(&m_pluginMutex); return m_plugin->contextMenuActions(items); } return QList(); @@ -137,6 +143,7 @@ QList RevisionControlObserver::contextMenuActions(const KFileItemList& QList RevisionControlObserver::contextMenuActions(const QString& directory) const { if (m_dolphinModel->hasRevisionData() && (m_plugin != 0)) { + QMutexLocker locker(&m_pluginMutex); return m_plugin->contextMenuActions(directory); } @@ -162,28 +169,44 @@ void RevisionControlObserver::verifyDirectory() revisionControlUrl.addPath(m_plugin->fileName()); const KFileItem item = m_dirLister->findByUrl(revisionControlUrl); - if (item.isNull() && m_revisionedDirectory) { - // 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); - m_revisionedDirectory = false; - disconnect(m_dirLister, SIGNAL(refreshItems(const QList>&)), - this, SLOT(delayedDirectoryVerification())); - disconnect(m_dirLister, SIGNAL(newItems(const KFileItemList&)), - this, SLOT(delayedDirectoryVerification())); - } else if (!item.isNull()) { + + bool foundRevisionInfo = !item.isNull(); + if (!foundRevisionInfo && m_revisionedDirectory) { + // Revision control systems like Git provide the revision information + // file only in the root directory. Check whether the revision information file can + // be found in one of the parent directories. + + // TODO... + } + + if (foundRevisionInfo) { if (!m_revisionedDirectory) { + m_revisionedDirectory = true; + // The directory is versioned. Assume that the user will further browse through // versioned directories and decrease the verification timer. m_dirVerificationTimer->setInterval(100); - m_revisionedDirectory = true; connect(m_dirLister, SIGNAL(refreshItems(const QList>&)), this, SLOT(delayedDirectoryVerification())); connect(m_dirLister, SIGNAL(newItems(const KFileItemList&)), this, SLOT(delayedDirectoryVerification())); + connect(m_plugin, SIGNAL(revisionStatesChanged(const QString&)), + this, SLOT(delayedDirectoryVerification())); } updateItemStates(); + } else if (m_revisionedDirectory) { + m_revisionedDirectory = false; + + // 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); + disconnect(m_dirLister, SIGNAL(refreshItems(const QList>&)), + this, SLOT(delayedDirectoryVerification())); + disconnect(m_dirLister, SIGNAL(newItems(const KFileItemList&)), + this, SLOT(delayedDirectoryVerification())); + disconnect(m_plugin, SIGNAL(revisionStatesChanged(const QString&)), + this, SLOT(delayedDirectoryVerification())); } } @@ -216,7 +239,7 @@ void RevisionControlObserver::updateItemStates() { Q_ASSERT(m_plugin != 0); if (m_updateItemStatesThread == 0) { - m_updateItemStatesThread = new UpdateItemStatesThread(this); + m_updateItemStatesThread = new UpdateItemStatesThread(this, &m_pluginMutex); connect(m_updateItemStatesThread, SIGNAL(finished()), this, SLOT(applyUpdatedItemStates())); } @@ -238,8 +261,8 @@ void RevisionControlObserver::updateItemStates() ItemState itemState; itemState.index = index; itemState.item = m_dolphinModel->itemForIndex(index); - itemState.revision = RevisionControlPlugin::LocalRevision; - + itemState.revision = RevisionControlPlugin::UnversionedRevision; + itemStates.append(itemState); } diff --git a/src/revisioncontrolobserver.h b/src/revisioncontrolobserver.h index 27c7a27a0e..ae19e219f6 100644 --- a/src/revisioncontrolobserver.h +++ b/src/revisioncontrolobserver.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,7 @@ private: QTimer* m_dirVerificationTimer; + mutable QMutex m_pluginMutex; RevisionControlPlugin* m_plugin; UpdateItemStatesThread* m_updateItemStatesThread; diff --git a/src/revisioncontrolplugin.cpp b/src/revisioncontrolplugin.cpp index b3b407c619..1e19ddcf0e 100644 --- a/src/revisioncontrolplugin.cpp +++ b/src/revisioncontrolplugin.cpp @@ -19,14 +19,6 @@ #include "revisioncontrolplugin.h" -#include -#include -#include -#include -#include -#include -#include - RevisionControlPlugin::RevisionControlPlugin() { } @@ -39,28 +31,59 @@ RevisionControlPlugin::~RevisionControlPlugin() // ---------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + SubversionPlugin::SubversionPlugin() : - m_directory(), + m_retrievalDir(), m_revisionInfoHash(), m_updateAction(0), + m_showLocalChangesAction(0), m_commitAction(0), m_addAction(0), - m_removeAction(0) + m_removeAction(0), + m_contextDir(), + m_contextItems() { m_updateAction = new KAction(this); m_updateAction->setIcon(KIcon("view-refresh")); m_updateAction->setText(i18nc("@item:inmenu", "SVN Update")); + connect(m_updateAction, SIGNAL(triggered()), + this, SLOT(updateFiles())); + + m_showLocalChangesAction = new KAction(this); + m_showLocalChangesAction->setIcon(KIcon("view-split-left-right")); + m_showLocalChangesAction->setText(i18nc("@item:inmenu", "Show Local SVN Changes")); + connect(m_showLocalChangesAction, SIGNAL(triggered()), + this, SLOT(showLocalChanges())); m_commitAction = new KAction(this); m_commitAction->setText(i18nc("@item:inmenu", "SVN Commit...")); + connect(m_commitAction, SIGNAL(triggered()), + this, SLOT(commitFiles())); m_addAction = new KAction(this); m_addAction->setIcon(KIcon("list-add")); m_addAction->setText(i18nc("@item:inmenu", "SVN Add")); + connect(m_addAction, SIGNAL(triggered()), + this, SLOT(addFiles())); m_removeAction = new KAction(this); m_removeAction->setIcon(KIcon("list-remove")); m_removeAction->setText(i18nc("@item:inmenu", "SVN Delete")); + connect(m_removeAction, SIGNAL(triggered()), + this, SLOT(removeFiles())); } SubversionPlugin::~SubversionPlugin() @@ -75,7 +98,7 @@ QString SubversionPlugin::fileName() const bool SubversionPlugin::beginRetrieval(const QString& directory) { Q_ASSERT(directory.endsWith('/')); - m_directory = directory; + m_retrievalDir = directory; const QString path = directory + ".svn/text-base/"; QDir dir(path); @@ -83,15 +106,16 @@ bool SubversionPlugin::beginRetrieval(const QString& directory) const int size = fileInfoList.size(); QString fileName; for (int i = 0; i < size; ++i) { - fileName = fileInfoList.at(i).fileName(); + const QFileInfo fileInfo = fileInfoList.at(i); + fileName = fileInfo.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()) { RevisionInfo info; - info.size = fileInfoList.at(i).size(); - info.timeStamp = fileInfoList.at(i).lastModified(); - m_revisionInfoHash.insert(fileName, info); + info.size = fileInfo.size(); + info.timeStamp = fileInfo.lastModified(); + m_revisionInfoHash.insert(directory + fileName, info); } } return size > 0; @@ -103,37 +127,63 @@ void SubversionPlugin::endRetrieval() RevisionControlPlugin::RevisionState SubversionPlugin::revisionState(const KFileItem& item) { - const QString name = item.name(); + const QString itemUrl = item.localPath(); if (item.isDir()) { - QFile file(m_directory + name + "/.svn"); + QFile file(itemUrl + "/.svn"); if (file.open(QIODevice::ReadOnly)) { file.close(); - // TODO... - return RevisionControlPlugin::LatestRevision; + return RevisionControlPlugin::NormalRevision; } - } else if (m_revisionInfoHash.contains(name)) { - const RevisionInfo info = m_revisionInfoHash.value(item.name()); + } else if (m_revisionInfoHash.contains(itemUrl)) { + const RevisionInfo info = m_revisionInfoHash.value(itemUrl); const QDateTime localTimeStamp = item.time(KFileItem::ModificationTime).dateTime(); const QDateTime versionedTimeStamp = info.timeStamp; if (localTimeStamp > versionedTimeStamp) { if ((info.size != item.size()) || !equalRevisionContent(item.name())) { - return RevisionControlPlugin::EditingRevision; + return RevisionControlPlugin::LocallyModifiedRevision; } } else if (localTimeStamp < versionedTimeStamp) { if ((info.size != item.size()) || !equalRevisionContent(item.name())) { return RevisionControlPlugin::UpdateRequiredRevision; } } - return RevisionControlPlugin::LatestRevision; + return RevisionControlPlugin::NormalRevision; } - return RevisionControlPlugin::LocalRevision; + return RevisionControlPlugin::UnversionedRevision; } -QList SubversionPlugin::contextMenuActions(const KFileItemList& items) const +QList SubversionPlugin::contextMenuActions(const KFileItemList& items) { - Q_UNUSED(items); + Q_ASSERT(!items.isEmpty()); + + m_contextItems = items; + m_contextDir.clear(); + + // iterate all items and check the revision state to know which + // actions can be enabled + const int itemsCount = items.count(); + int revisionedCount = 0; + int editingCount = 0; + foreach (const KFileItem& item, items) { + const RevisionState state = revisionState(item); + if (state != UnversionedRevision) { + ++revisionedCount; + } + + switch (state) { + case LocallyModifiedRevision: + case ConflictingRevision: + ++editingCount; + break; + default: + break; + } + } + m_commitAction->setEnabled(editingCount > 0); + m_addAction->setEnabled(revisionedCount == 0); + m_removeAction->setEnabled(revisionedCount == itemsCount); QList actions; actions.append(m_updateAction); @@ -143,24 +193,90 @@ QList SubversionPlugin::contextMenuActions(const KFileItemList& items) return actions; } -QList SubversionPlugin::contextMenuActions(const QString& directory) const +QList SubversionPlugin::contextMenuActions(const QString& directory) { - Q_UNUSED(directory); + m_contextDir = directory; + m_contextItems.clear(); QList actions; actions.append(m_updateAction); + actions.append(m_showLocalChangesAction); actions.append(m_commitAction); return actions; } +void SubversionPlugin::updateFiles() +{ + execSvnCommand("update"); +} + +void SubversionPlugin::showLocalChanges() +{ + Q_ASSERT(!m_contextDir.isEmpty()); + Q_ASSERT(m_contextItems.isEmpty()); + + const QString command = "mkfifo /tmp/fifo; svn diff " + + KShell::quoteArg(m_contextDir) + + " > /tmp/fifo & kompare /tmp/fifo; rm /tmp/fifo"; + KRun::runCommand(command, 0); +} + +void SubversionPlugin::commitFiles() +{ + KDialog dialog(0, Qt::Dialog); + + KVBox* box = new KVBox(&dialog); + new QLabel(i18nc("@label", "Description:"), box); + QTextEdit* editor = new QTextEdit(box); + + dialog.setMainWidget(box); + dialog.setCaption(i18nc("@title:window", "SVN Commit")); + dialog.setButtons(KDialog::Ok | KDialog::Cancel); + dialog.setDefaultButton(KDialog::Ok); + dialog.setButtonText(KDialog::Ok, i18nc("@action:button", "Commit")); + + KConfigGroup dialogConfig(KSharedConfig::openConfig("dolphinrc"), + "SvnCommitDialog"); + dialog.restoreDialogSize(dialogConfig); + + if (dialog.exec() == QDialog::Accepted) { + const QString description = editor->toPlainText(); + execSvnCommand("commit -m " + KShell::quoteArg(description)); + } + + dialog.saveDialogSize(dialogConfig, KConfigBase::Persistent); +} + +void SubversionPlugin::addFiles() +{ + execSvnCommand("add"); +} + +void SubversionPlugin::removeFiles() +{ + execSvnCommand("remove"); +} + +void SubversionPlugin::execSvnCommand(const QString& svnCommand) +{ + const QString command = "svn " + svnCommand + ' '; + if (!m_contextDir.isEmpty()) { + KRun::runCommand(command + KShell::quoteArg(m_contextDir), 0); + } else { + foreach (const KFileItem& item, m_contextItems) { + KRun::runCommand(command + KShell::quoteArg(item.localPath()), 0); + } + } +} + bool SubversionPlugin::equalRevisionContent(const QString& name) const { - QFile localFile(m_directory + '/' + name); + QFile localFile(m_retrievalDir + '/' + name); if (!localFile.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } - QFile revisionedFile(m_directory + "/.svn/text-base/" + name + ".svn-base"); + QFile revisionedFile(m_retrievalDir + "/.svn/text-base/" + name + ".svn-base"); if (!revisionedFile.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } @@ -175,4 +291,3 @@ bool SubversionPlugin::equalRevisionContent(const QString& name) const return localText.atEnd() && revisionedText.atEnd(); } - diff --git a/src/revisioncontrolplugin.h b/src/revisioncontrolplugin.h index bbe66b3c3b..7863cfacb3 100644 --- a/src/revisioncontrolplugin.h +++ b/src/revisioncontrolplugin.h @@ -34,13 +34,7 @@ class QAction; * @brief Base class for revision control plugins. * * Enables the file manager to show the revision state - * of a revisioned file. The methods - * RevisionControlPlugin::beginRetrieval(), - * RevisionControlPlugin::endRetrieval() and - * RevisionControlPlugin::revisionState() are invoked - * from a separate thread to assure that the GUI thread - * won't be blocked. All other methods are invoked in the - * scope of the GUI thread. + * of a revisioned file. */ class LIBDOLPHINPRIVATE_EXPORT RevisionControlPlugin : public QObject { @@ -49,12 +43,34 @@ class LIBDOLPHINPRIVATE_EXPORT RevisionControlPlugin : public QObject public: enum RevisionState { - LocalRevision, - LatestRevision, + /** The file is not under revision control. */ + UnversionedRevision, + /** + * The file is under revision control and represents + * the latest version. + */ + NormalRevision, + /** + * The file is under revision control and a newer + * version exists on the main branch. + */ UpdateRequiredRevision, - EditingRevision, + /** + * The file is under revision control and has been + * modified locally. + */ + LocallyModifiedRevision, + /** + * The file has not been under revision control but + * has been marked to get added with the next commit. + */ + AddedRevision, + /** + * The file is under revision control and has been locally + * modified. A modification has also been done on the main + * branch. + */ ConflictingRevision - // TODO... }; RevisionControlPlugin(); @@ -97,14 +113,14 @@ public: * If an action triggers a change of the revisions, the signal * RevisionControlPlugin::revisionStatesChanged() must be emitted. */ - virtual QList contextMenuActions(const KFileItemList& items) const = 0; + virtual QList contextMenuActions(const KFileItemList& items) = 0; /** * Returns the list of actions that should be shown in the context menu * for the directory \p directory. If an action triggers a change of the revisions, * the signal RevisionControlPlugin::revisionStatesChanged() must be emitted. */ - virtual QList contextMenuActions(const QString& directory) const = 0; + virtual QList contextMenuActions(const QString& directory) = 0; signals: /** @@ -124,11 +140,13 @@ signals: // TODO: This is just a temporary test class. It will be made available as // plugin outside Dolphin later. -#include +#include #include class LIBDOLPHINPRIVATE_EXPORT SubversionPlugin : public RevisionControlPlugin { + Q_OBJECT + public: SubversionPlugin(); virtual ~SubversionPlugin(); @@ -136,10 +154,23 @@ public: virtual bool beginRetrieval(const QString& directory); virtual void endRetrieval(); virtual RevisionControlPlugin::RevisionState revisionState(const KFileItem& item); - virtual QList contextMenuActions(const KFileItemList& items) const; - virtual QList contextMenuActions(const QString& directory) const; + virtual QList contextMenuActions(const KFileItemList& items); + virtual QList contextMenuActions(const QString& directory); + +private slots: + void updateFiles(); + void showLocalChanges(); + void commitFiles(); + void addFiles(); + void removeFiles(); private: + /** + * Executes the command "svn {svnCommand}" for the files that have been + * set by getting the context menu actions (see contextMenuActions()). + */ + void execSvnCommand(const QString& svnCommand); + /** * Returns true, if the content of the local file \p name is equal to the * content of the revisioned file. @@ -153,13 +184,16 @@ private: QDateTime timeStamp; }; - QString m_directory; + QString m_retrievalDir; QHash m_revisionInfoHash; QAction* m_updateAction; + QAction* m_showLocalChangesAction; QAction* m_commitAction; QAction* m_addAction; QAction* m_removeAction; + mutable QString m_contextDir; + mutable KFileItemList m_contextItems; }; #endif // REVISIONCONTROLPLUGIN_H