[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    =?utf-8?q?=5Bkdevplatform=5D_/=3A_Introduce_and_integrate_VcsFil?=
From:       Andrey Batyiev <batyiev () gmail ! com>
Date:       2011-05-01 20:56:14
Message-ID: 20110501205614.01BEBA60A4 () git ! kde ! org
[Download RAW message or body]

Git commit 85bfe7888d9e3fd4f015e106ef15fa04063be739 by Andrey Batyiev.
Committed on 01/05/2011 at 22:55.
Pushed by abatyiev into branch 'master'.

Introduce and integrate VcsFileChangesModel.

REVIEW: 101145

M  +1    -1    plugins/patchreview/CMakeLists.txt     
M  +67   -184  plugins/patchreview/patchreview.cpp     
M  +3    -0    plugins/patchreview/patchreview.h     
M  +1    -6    plugins/patchreview/patchreview.ui     
M  +3    -0    vcs/CMakeLists.txt     
A  +11   -0    vcs/models/tests/CMakeLists.txt         [License: UNKNOWN]  *
A  +125  -0    vcs/models/tests/modelstest.cpp         [License: GPL (v2/3)]
A  +35   -0    vcs/models/tests/modelstest.h         [License: GPL (v2/3)]
A  +184  -0    vcs/models/vcsfilechangesmodel.cpp         [License: LGPL (v2+)]
A  +127  -0    vcs/models/vcsfilechangesmodel.h         [License: LGPL (v2+)]
M  +7    -77   vcs/widgets/vcscommitdialog.cpp     
M  +5    -23   vcs/widgets/vcscommitdialog.ui     

The files marked with a * at the end have a non valid license. Please read: \
http://techbase.kde.org/Policies/Licensing_Policy and use the headers which are \
listed at that page.


http://commits.kde.org/kdevplatform/85bfe7888d9e3fd4f015e106ef15fa04063be739

diff --git a/plugins/patchreview/CMakeLists.txt b/plugins/patchreview/CMakeLists.txt
index 222e28f..ddd01b7 100644
--- a/plugins/patchreview/CMakeLists.txt
+++ b/plugins/patchreview/CMakeLists.txt
@@ -33,7 +33,7 @@ kde4_add_ui_files(patchreview_PART_SRCS ${patchreview_UI} )
 
 
 kde4_add_plugin(kdevpatchreview ${patchreview_PART_SRCS})
-target_link_libraries(kdevpatchreview ${KDE4_KDEUI_LIBS} ${KDE4_KTEXTEDITOR_LIBS} \
${KDE4_KPARTS_LIBS} kdevplatforminterfaces kdevplatformutil kdevplatformlanguage \
${KDE4_KDE3SUPPORT_LIBS} sublime) +target_link_libraries(kdevpatchreview \
${KDE4_KDEUI_LIBS} ${KDE4_KTEXTEDITOR_LIBS} ${KDE4_KPARTS_LIBS} \
kdevplatforminterfaces kdevplatformutil kdevplatformlanguage \
${KDEVPLATFORM_VCS_LIBRARIES} ${KDE4_KDE3SUPPORT_LIBS} sublime)  
 install(TARGETS kdevpatchreview DESTINATION ${PLUGIN_INSTALL_DIR})
 
diff --git a/plugins/patchreview/patchreview.cpp \
b/plugins/patchreview/patchreview.cpp index 2811869..e80cdb1 100644
--- a/plugins/patchreview/patchreview.cpp
+++ b/plugins/patchreview/patchreview.cpp
@@ -74,6 +74,8 @@ std::string*/
 #include <interfaces/ipatchexporter.h>
 #include "standardpatchexport.h"
 #include <language/highlighting/colorcache.h>
+#include <vcs/models/vcsfilechangesmodel.h>
+#include <shell/core.h>
 
 using namespace KDevelop;
 
@@ -84,6 +86,43 @@ namespace {
 
 Q_DECLARE_METATYPE( const Diff2::DiffModel* )
 
+
+class PatchFilesModel : public VcsFileChangesModel
+{
+public:
+  PatchFilesModel(QObject *parent, bool allowSelection = false) : \
VcsFileChangesModel(parent, allowSelection) { }; +  enum ItemRoles { HunksNumberRole \
= VcsStatusInfoRole+1 }; +
+public slots:
+  void updateState(const KDevelop::VcsStatusInfo &status, unsigned hunksNum) {
+      int row = VcsFileChangesModel::updateState(invisibleRootItem(), status);
+      if (row == -1)
+        return;
+
+      QStandardItem *item = invisibleRootItem()->child(row, 0);
+      setFileInfo(item, hunksNum);
+      item->setData(QVariant(hunksNum), HunksNumberRole);
+  }
+
+  void updateState(const KDevelop::VcsStatusInfo &status) {
+      int row = VcsFileChangesModel::updateState(invisibleRootItem(), status);
+      if (row == -1)
+        return;
+
+      QStandardItem *item = invisibleRootItem()->child(row, 0);
+      setFileInfo(invisibleRootItem()->child(row, 0), \
item->data(HunksNumberRole).toUInt()); +  }
+
+private:
+  void setFileInfo(QStandardItem *item, unsigned int hunksNum) {
+    QString newText = i18ncp("%1: number of changed hunks, %2: file name",
+                             "%2 (1 hunk)", "%2 (%1 hunks)", hunksNum, \
item->text()); +    item->setText(newText);
+  }
+};
+
+
+
 PatchReviewToolView::PatchReviewToolView( QWidget* parent, PatchReviewPlugin* plugin \
)   : QWidget( parent ), m_reversed( false ), m_plugin( plugin ) 
 {
@@ -203,7 +242,7 @@ void PatchReviewToolView::fillEditFromPatch() {
 
 void PatchReviewToolView::patchSelectionChanged(int selection)
 {
-  m_editPatch.filesList->clear();
+    m_fileModel->removeRows(0, m_fileModel->rowCount());
     if(selection >= 0 && selection < m_plugin->knownPatches().size()) {
       m_plugin->setPatch(m_plugin->knownPatches()[selection]);
     }
@@ -239,6 +278,8 @@ void PatchReviewToolView::showEditDialog() {
 
     m_editPatch.setupUi( this );
 
+    m_fileModel = new PatchFilesModel(this, true);
+    m_editPatch.filesList->setModel(m_fileModel);
     m_editPatch.filesList->header()->hide();
     m_editPatch.filesList->setRootIsDecorated(false);
     
@@ -439,58 +480,19 @@ void PatchReviewPlugin::highlightPatch() {
 
 void PatchReviewToolView::finishReview()
 {
-    QList<KUrl> selectedUrls;
-    for(int a = 0; a< m_editPatch.filesList->topLevelItemCount(); ++a) {
-      QTreeWidgetItem* item = m_editPatch.filesList->topLevelItem(a);
-      if(item && item->checkState(0) == Qt::Checked) {
-        QVariant v = item->data(0, Qt::UserRole);
-        
-        if( v.canConvert<KUrl>() ) {
-          selectedUrls << v.value<KUrl>();
-        }else if ( v.canConvert<const Diff2::DiffModel*>() ) {
-          const Diff2::DiffModel* model = v.value<const Diff2::DiffModel*>();
-
-          KUrl file = m_plugin->urlForFileModel( model );
-
-          selectedUrls << file;
-        }
-      }
-    }
+    QList<KUrl> selectedUrls = m_fileModel->checkedUrls();
     kDebug() << "finishing review with" << selectedUrls;
     m_plugin->finishReview(selectedUrls);
 }
 
 void PatchReviewToolView::fileDoubleClicked( const QModelIndex& i ) {
-    try {
-        if ( !m_plugin->modelList() )
-            throw "no model";
-        
-        QVariant v = i.data( Qt::UserRole );
-        
-        if( v.canConvert<KUrl>() ) {
-          KUrl u = v.value<KUrl>();
-          ICore::self()->documentController()->openDocument( u, \
                KTextEditor::Cursor() );
-          return;
-        }
-        
-        if ( !v.canConvert<const Diff2::DiffModel*>() )
-            throw "cannot convert";
-        const Diff2::DiffModel* model = v.value<const Diff2::DiffModel*>();
-        if ( !model )
-            throw "bad model-value";
+    KUrl file = m_fileModel->statusInfo( i ).url();
 
-        KUrl file = m_plugin->urlForFileModel( model );
+    kDebug() << "opening" << file.toLocalFile();
 
-        kDebug() << "opening" << file.toLocalFile();
+    ICore::self()->documentController()->openDocument( file, KTextEditor::Cursor() \
);  
-        ICore::self()->documentController()->openDocument( file, \
                KTextEditor::Cursor() );
-
-        m_plugin->seekHunk( true, file );
-    } catch ( const QString & str ) {
-        kDebug() << "fileDoubleClicked():" << str;
-    } catch ( const char * str ) {
-        kDebug() << "fileDoubleClicked():" << str;
-    }
+    m_plugin->seekHunk( true, file );
 }
 
 KUrl PatchReviewPlugin::urlForFileModel(const Diff2::DiffModel* model)
@@ -503,60 +505,15 @@ KUrl PatchReviewPlugin::urlForFileModel(const Diff2::DiffModel* \
model)  return file;
 }
 
-static QString stateToString(KDevelop::VcsStatusInfo::State state)
-{
-    switch(state)
-    {
-      case KDevelop::VcsStatusInfo::ItemAdded:
-          return i18nc("VCS file status", "Added");
-      case KDevelop::VcsStatusInfo::ItemDeleted:
-          return i18nc("VCS file status", "Deleted");
-      case KDevelop::VcsStatusInfo::ItemHasConflicts:
-          return i18nc("VCS file status", "Has Conflicts");
-      case KDevelop::VcsStatusInfo::ItemModified:
-          return i18nc("VCS file status", "Modified");
-      case KDevelop::VcsStatusInfo::ItemUpToDate:
-          return i18nc("VCS file status", "Up To Date");
-      case KDevelop::VcsStatusInfo::ItemUnknown:
-      case KDevelop::VcsStatusInfo::ItemUserState:
-          return i18nc("VCS file status", "Unknown");
-    }
-    return i18nc("Unknown VCS file status, probably a backend error", "?");
-}
-
-static KIcon stateToIcon(KDevelop::VcsStatusInfo::State state)
-{
-    switch(state)
-    {
-      case KDevelop::VcsStatusInfo::ItemAdded:
-          return KIcon("vcs-added");
-      case KDevelop::VcsStatusInfo::ItemDeleted:
-          return KIcon("vcs-removed");
-      case KDevelop::VcsStatusInfo::ItemHasConflicts:
-          return KIcon("vcs-conflicting");
-      case KDevelop::VcsStatusInfo::ItemModified:
-          return KIcon("vcs-locally-modified");
-      case KDevelop::VcsStatusInfo::ItemUpToDate:
-          return KIcon("vcs-normal");
-      case KDevelop::VcsStatusInfo::ItemUnknown:
-      case KDevelop::VcsStatusInfo::ItemUserState:
-          return KIcon("unknown");
-    }
-    return KIcon("dialog-error");
-}
-
 void PatchReviewToolView::kompareModelChanged()
 {
-    m_editPatch.filesList->clear();
-    m_editPatch.filesList->setColumnCount(1);
+    m_fileModel->removeRows(0, m_fileModel->rowCount());
 
     if (!m_plugin->modelList())
         return;
 
     QMap<KUrl, KDevelop::VcsStatusInfo::State> additionalUrls = \
m_plugin->patch()->additionalSelectableFiles();  
-    QSet<KUrl> haveUrls;
-    
     const Diff2::DiffModelList* models = m_plugin->modelList()->models();
     if( models )
     {
@@ -568,88 +525,25 @@ void PatchReviewToolView::kompareModelChanged()
               cnt = diffs->count();
 
           KUrl file = m_plugin->urlForFileModel(*it);
-          haveUrls.insert(file);
-
           if(!QFileInfo(file.toLocalFile()).isReadable())
             continue;
-            
-          QTreeWidgetItem* item = new QTreeWidgetItem(m_editPatch.filesList);
-          
-          m_editPatch.filesList->insertTopLevelItem(0, item);
-
-          const QString filenameArgument = \
ICore::self()->projectController()->prettyFileName(file, \
                KDevelop::IProjectController::FormatPlain);
-
-          QString text;
-          QIcon icon;
-          if(additionalUrls.contains(file)) {
-              text = i18ncp("%1: number of changed hunks, %2: file name, %3: vcs \
                file state",
-                "%2 (1 hunk, %3)", "%2 (%1 hunks, %3)", cnt, filenameArgument, \
                stateToString(additionalUrls[file]));
-              icon = stateToIcon(additionalUrls[file]);
-          } else {
-              text = i18ncp("%1: number of changed hunks, %2: file name",
-                "%2 (1 hunk)", "%2 (%1 hunks)", cnt, filenameArgument);
-          }
 
-          item->setData( 0, Qt::DisplayRole, text );
-          item->setIcon( 0, icon );
-          item->setData( 0, Qt::UserRole, qVariantFromValue<const \
                Diff2::DiffModel*>(*it));
-          item->setCheckState( 0, Qt::Checked );
-      }
-    }
-    
-    // Maps the _really_ useful items (with VCS state) to index 0,
-    // the items that have at least a project found to 1,
-    // and the probably really useless items without project found to 2.
-    // The project-manager filters useless stuff like backups out so they get index \
                2.
-    QMap<int, QList< QPair<KUrl, KDevelop::VcsStatusInfo::State> > > newItems;
-    
-    for(QMap<KUrl, KDevelop::VcsStatusInfo::State>::const_iterator it = \
                additionalUrls.constBegin(); it != additionalUrls.constEnd(); ++it)
-    {
-      KUrl url = it.key();
-      
-      if(!haveUrls.contains(url))
-      {
-        haveUrls.insert(url);
-        
-        if(*it != KDevelop::VcsStatusInfo::ItemUnknown)
-        {
-          newItems[0] << qMakePair(url, *it);
-        }else{
-          if(((bool)ICore::self()->projectController()->findProjectForUrl(url)))
-          {
-            newItems[1] << qMakePair(url, *it);
-          }else{
-            newItems[2] << qMakePair(url, *it);
-          }
-        }
+          VcsStatusInfo status;
+          status.setUrl(file);
+          status.setState(VcsStatusInfo::ItemModified);
+
+          m_fileModel->updateState(status, cnt);
       }
     }
-    
-    for(int a = 0; a < 3; ++a)
-    {
-      for(QList< QPair< KUrl, KDevelop::VcsStatusInfo::State > >::iterator itemIt = \
                newItems[a].begin(); itemIt != newItems[a].end(); ++itemIt)
-      {
-        KUrl url = itemIt->first;
-        KDevelop::VcsStatusInfo::State state = itemIt->second;
-        
-        QTreeWidgetItem* item = new QTreeWidgetItem(m_editPatch.filesList);
-        
-        QString text = ICore::self()->projectController()->prettyFileName(url, \
                KDevelop::IProjectController::FormatPlain);
-        text += " (" + stateToString(state) + ")";
-        
-        item->setData( 0, Qt::DisplayRole, text );
-        QVariant v;
-        v.setValue<KUrl>( url );
-        item->setData( 0, Qt::UserRole, v );
-        item->setIcon( 0, stateToIcon(state) );
-        item->setCheckState( 0, Qt::Unchecked );
-
-        if(a == 0)
-          item->setCheckState( 0, Qt::Checked );
-        
-        m_editPatch.filesList->addTopLevelItem(item);
-      }
+
+    for(QMap<KUrl, KDevelop::VcsStatusInfo::State>::const_iterator it = \
additionalUrls.constBegin(); it != additionalUrls.constEnd(); it++) { +        \
VcsStatusInfo status; +        status.setUrl(it.key());
+        status.setState(it.value());
+        m_fileModel->updateState(status);
     }
+
+    m_editPatch.filesList->resizeColumnToContents(0);
 }
 
 
@@ -658,23 +552,12 @@ void PatchReviewToolView::documentActivated(IDocument* doc)
     QModelIndexList i = m_editPatch.filesList->selectionModel() ->selectedIndexes();
     if ( !m_plugin->modelList() )
         return ;
-    for(int a = 0; a < m_editPatch.filesList->topLevelItemCount(); ++a) {
-      
-        QTreeWidgetItem* item = m_editPatch.filesList->topLevelItem(a);
-      
-        QVariant v = item->data( 0, Qt::UserRole );
-        if ( v.canConvert<const Diff2::DiffModel*>() ) {
-            const Diff2::DiffModel * model = v.value<const Diff2::DiffModel*>();
-
-            KUrl file = m_plugin->urlForFileModel(model);
-
-            if(file == doc->url()) {
-              m_editPatch.filesList->setCurrentItem(item);
-              return;
-            }
-        }
+    QStandardItem *fileItem = m_fileModel->fileItemForUrl(doc->url());
+    if (fileItem) {
+        m_editPatch.filesList->setCurrentIndex(fileItem->index());
+    } else {
+        m_editPatch.filesList->setCurrentIndex(QModelIndex());
     }
-    m_editPatch.filesList->setCurrentIndex(QModelIndex());
 }
 
 void PatchHighlighter::aboutToDeleteMovingInterfaceContent(KTextEditor::Document* )
diff --git a/plugins/patchreview/patchreview.h b/plugins/patchreview/patchreview.h
index eb0bc38..8e86063 100644
--- a/plugins/patchreview/patchreview.h
+++ b/plugins/patchreview/patchreview.h
@@ -50,6 +50,7 @@ class Info;
 }
 namespace KDevelop {
 class IDocument;
+class VcsFileChangesModel;
 }
 
 ///Delete itself when the document(or textDocument), or Diff-Model is deleted.
@@ -144,6 +145,8 @@ private:
     PatchReviewPlugin* m_plugin;
     
     QPointer<QWidget> m_customWidget;
+
+    class PatchFilesModel* m_fileModel;
 public slots:
     void documentActivated(KDevelop::IDocument*);
     void patchSelectionChanged(int);
diff --git a/plugins/patchreview/patchreview.ui b/plugins/patchreview/patchreview.ui
index 8fe9cd1..9d52dac 100644
--- a/plugins/patchreview/patchreview.ui
+++ b/plugins/patchreview/patchreview.ui
@@ -285,15 +285,10 @@
          <number>0</number>
         </property>
         <item row="0" column="0" rowspan="2">
-         <widget class="QTreeWidget" name="filesList">
+         <widget class="QTreeView" name="filesList">
           <property name="editTriggers">
            <set>QAbstractItemView::NoEditTriggers</set>
           </property>
-          <column>
-           <property name="text">
-            <string notr="true">1</string>
-           </property>
-          </column>
          </widget>
         </item>
        </layout>
diff --git a/vcs/CMakeLists.txt b/vcs/CMakeLists.txt
index f3cd726..5fedee8 100644
--- a/vcs/CMakeLists.txt
+++ b/vcs/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_subdirectory(dvcs/tests)
+add_subdirectory(models/tests)
 add_subdirectory(tests)
 
 add_definitions(-DKDE_DEFAULT_DEBUG_AREA=9509)
@@ -32,6 +33,7 @@ set(kdevplatformvcs_LIB_SRCS
     widgets/standardvcslocationwidget.cpp
     models/vcsannotationmodel.cpp
     models/vcseventmodel.cpp
+    models/vcsfilechangesmodel.cpp
     models/vcsitemeventmodel.cpp
     dvcs/dvcsjob.cpp
     dvcs/dvcsplugin.cpp
@@ -91,6 +93,7 @@ install(FILES
 install(FILES
     models/vcsannotationmodel.h
     models/vcseventmodel.h
+    models/vcsfilechangesmodel.h
     models/vcsitemeventmodel.h
     DESTINATION ${INCLUDE_INSTALL_DIR}/kdevplatform/vcs/models COMPONENT Devel
 )
diff --git a/vcs/models/tests/CMakeLists.txt b/vcs/models/tests/CMakeLists.txt
new file mode 100644
index 0000000..e6b6942
--- /dev/null
+++ b/vcs/models/tests/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
+set(modelsTest_SRCS modelstest.cpp)
+kde4_add_unit_test(modelsTest ${modelsTest_SRCS})
+target_link_libraries(modelsTest
+                      ${QT_QTTEST_LIBRARY}
+                      ${QT_QTGUI_LIBRARY}
+                      ${KDE4_KDECORE_LIBS}
+                      ${KDEVPLATFORM_TESTS_LIBRARIES}
+                      kdevplatformutil
+                      kdevplatformvcs
+                      )
diff --git a/vcs/models/tests/modelstest.cpp b/vcs/models/tests/modelstest.cpp
new file mode 100644
index 0000000..0af6ffd
--- /dev/null
+++ b/vcs/models/tests/modelstest.cpp
@@ -0,0 +1,125 @@
+/***************************************************************************
+ *   Copyright 2011 Andrey Batyiev <batyiev@gmail.com>                     *
+ *                                                                         *
+ *   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) version 3 or any later version        *
+ *   accepted by the membership of KDE e.V. (or its successor approved     *
+ *   by the membership of KDE e.V.), which shall act as a proxy            *
+ *   defined in Section 14 of version 3 of the license.                    *
+ *                                                                         *
+ *   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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include "modelstest.h"
+
+#include <QtTest/QtTest>
+#include <qtest_kde.h>
+
+#include <vcs/models/vcsfilechangesmodel.h>
+#include <tests/autotestshell.h>
+#include <tests/testcore.h>
+
+using namespace KDevelop;
+
+void ModelsTest::testInit()
+{
+    AutoTestShell::init();
+    Core::initialize();
+}
+
+
+void ModelsTest::testVcsFileChangesModel()
+{
+    VcsFileChangesModel *model = new VcsFileChangesModel(this);
+
+    // Newly created model should be empty
+    QVERIFY(model->rowCount() == 0);
+
+    // Pull some files into
+    QString filenames[] = {"foo", "bar", "pew", "trash"};
+    VcsStatusInfo::State states[] = {VcsStatusInfo::ItemAdded, \
VcsStatusInfo::ItemModified, VcsStatusInfo::ItemDeleted, \
VcsStatusInfo::ItemUpToDate}; +    VcsStatusInfo status;
+
+    for(int i = 0; i < 3; i++) {
+        status.setUrl(KUrl(filenames[i]));
+        status.setState(states[i]);
+        model->updateState(status);
+        QVERIFY(model->rowCount() == (i+1));
+    }
+
+    // Pulling up-to-date file doesn't change anything
+    {
+        status.setUrl(KUrl(filenames[3]));
+        status.setState(states[3]);
+        model->updateState(status);
+        QVERIFY(model->rowCount() == 3);
+    }
+
+    // Check that all OK
+    for(int i = 0; i < 3; i++) {
+        QStandardItem* item = model->fileItemForUrl(filenames[i]);
+        QVERIFY(item);
+        VcsStatusInfo info = VcsFileChangesModel::statusInfo(item);
+        QVERIFY(info.url().toLocalFile() == filenames[i]);
+        QVERIFY(info.state() == states[i]);
+    }
+
+    // Pull it all again = nothing changed
+    for(int i = 0; i < 3; i++) {
+        status.setUrl(KUrl(filenames[i]));
+        status.setState(states[i]);
+        model->updateState(status);
+        QVERIFY(model->rowCount() == 3);
+    }
+
+    // Check that all OK
+    for(int i = 0; i < 3; i++) {
+        QStandardItem* item = model->fileItemForUrl(filenames[i]);
+        QVERIFY(item);
+        VcsStatusInfo info = VcsFileChangesModel::statusInfo(item);
+        QVERIFY(info.url().toLocalFile() == filenames[i]);
+        QVERIFY(info.state() == states[i]);
+    }
+
+    // Remove one file
+    {
+        states[1] = VcsStatusInfo::ItemUpToDate;
+        status.setUrl(KUrl(filenames[1]));
+        status.setState(states[1]);
+        model->updateState(status);
+        QVERIFY(model->rowCount() == 2);
+    }
+
+    // Check them all
+    for(int i = 0; i < 3; i++) {
+        if(states[i] != VcsStatusInfo::ItemUpToDate && states[i] != \
VcsStatusInfo::ItemUnknown) { +            QStandardItem* item = \
model->fileItemForUrl(filenames[i]); +            QVERIFY(item);
+            VcsStatusInfo info = VcsFileChangesModel::statusInfo(item);
+            QVERIFY(info.url().toLocalFile() == filenames[i]);
+            QVERIFY(info.state() == states[i]);
+        }
+    }
+
+    // Delete them all
+    model->removeRows(0, model->rowCount());
+    QVERIFY(model->rowCount() == 0);
+
+    // Pull it all again
+    for(int i = 0; i < 3; i++) {
+        status.setUrl(KUrl(filenames[i]));
+        status.setState(states[i]);
+        model->updateState(status);
+    }
+    QVERIFY(model->rowCount() == 2);
+}
+
+QTEST_KDEMAIN(ModelsTest, GUI);
diff --git a/vcs/models/tests/modelstest.h b/vcs/models/tests/modelstest.h
new file mode 100644
index 0000000..81587d6
--- /dev/null
+++ b/vcs/models/tests/modelstest.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ *   Copyright 2011 Andrey Batyiev <batyiev@gmail.com>                     *
+ *                                                                         *
+ *   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) version 3 or any later version        *
+ *   accepted by the membership of KDE e.V. (or its successor approved     *
+ *   by the membership of KDE e.V.), which shall act as a proxy            *
+ *   defined in Section 14 of version 3 of the license.                    *
+ *                                                                         *
+ *   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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef MODELSTEST_H
+#define MODELSTEST_H
+
+#include <QObject>
+
+
+class ModelsTest : public QObject
+{
+    Q_OBJECT
+private slots:
+    void testInit();
+    void testVcsFileChangesModel();
+};
+
+#endif // MODELSTEST_H
diff --git a/vcs/models/vcsfilechangesmodel.cpp b/vcs/models/vcsfilechangesmodel.cpp
new file mode 100644
index 0000000..ff87e8b
--- /dev/null
+++ b/vcs/models/vcsfilechangesmodel.cpp
@@ -0,0 +1,184 @@
+/*  This file is part of KDevelop
+    Copyright 2010 Aleix Pol <aleixpol@kde.org>
+
+    Splitted into separate class
+    Copyright 2011 Andrey Batyiev <batyiev@gmail.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include <KLocale>
+#include <KIcon>
+#include <KMimeType>
+#include <KDebug>
+
+#include <interfaces/icore.h>
+#include <interfaces/iprojectcontroller.h>
+
+#include <vcs/vcsstatusinfo.h>
+
+#include "vcsfilechangesmodel.h"
+
+namespace KDevelop
+{
+
+static QString stateToString(KDevelop::VcsStatusInfo::State state)
+{
+    switch(state)
+    {
+        case KDevelop::VcsStatusInfo::ItemAdded:
+            return i18nc("file was added to versioncontrolsystem", "Added");
+        case KDevelop::VcsStatusInfo::ItemDeleted:
+            return i18nc("file was deleted from versioncontrolsystem", "Deleted");
+        case KDevelop::VcsStatusInfo::ItemHasConflicts:
+            return i18nc("file is confilicting (versioncontrolsystem)", "Has \
Conflicts"); +        case KDevelop::VcsStatusInfo::ItemModified:
+            return i18nc("version controlled file was modified", "Modified");
+        case KDevelop::VcsStatusInfo::ItemUpToDate:
+            return i18nc("file is up to date in versioncontrolsystem", "Up To \
Date"); +        case KDevelop::VcsStatusInfo::ItemUnknown:
+        case KDevelop::VcsStatusInfo::ItemUserState:
+            return i18nc("file is not known to versioncontrolsystem", "Unknown");
+    }
+    return i18nc("Unknown VCS file status, probably a backend error", "?");
+}
+
+static KIcon stateToIcon(KDevelop::VcsStatusInfo::State state)
+{
+    switch(state)
+    {
+        case KDevelop::VcsStatusInfo::ItemAdded:
+            return KIcon("vcs-added");
+        case KDevelop::VcsStatusInfo::ItemDeleted:
+            return KIcon("vcs-removed");
+        case KDevelop::VcsStatusInfo::ItemHasConflicts:
+            return KIcon("vcs-conflicting");
+        case KDevelop::VcsStatusInfo::ItemModified:
+            return KIcon("vcs-locally-modified");
+        case KDevelop::VcsStatusInfo::ItemUpToDate:
+            return KIcon("vcs-normal");
+        case KDevelop::VcsStatusInfo::ItemUnknown:
+        case KDevelop::VcsStatusInfo::ItemUserState:
+            return KIcon("unknown");
+    }
+    return KIcon("dialog-error");
+}
+
+class VcsFileChangesModelPrivate
+{
+public:
+    bool allowSelection;
+};
+
+VcsFileChangesModel::VcsFileChangesModel(QObject *parent, bool allowSelection)
+    : QStandardItemModel(parent), d(new VcsFileChangesModelPrivate)
+{
+    setColumnCount(2);
+    setHeaderData(0, Qt::Horizontal, i18n("Filename"));
+    setHeaderData(1, Qt::Horizontal, i18n("Status"));
+    d->allowSelection = allowSelection;
+}
+
+int VcsFileChangesModel::updateState(QStandardItem *parent, const \
KDevelop::VcsStatusInfo &status) +{
+    QStandardItem* it1=0;
+    QStandardItem* itStatus;
+
+    it1=fileItemForUrl(parent, status.url());
+
+    if(status.state()==VcsStatusInfo::ItemUnknown || \
status.state()==VcsStatusInfo::ItemUpToDate) { +        if(it1)
+            parent->removeRow(it1->row());
+        return -1;
+    } else {
+        if(!it1) {
+            QString path = \
ICore::self()->projectController()->prettyFileName(status.url(), \
KDevelop::IProjectController::FormatPlain); +            KIcon \
icon(KMimeType::findByUrl(status.url(), 0, false, true)->iconName(status.url())); +   \
it1 = new QStandardItem(icon, path); +            itStatus = new QStandardItem;
+
+            if(d->allowSelection) {
+                it1->setCheckable(true);
+                it1->setCheckState(status.state() == VcsStatusInfo::ItemUnknown ? \
Qt::Unchecked : Qt::Checked); +            }
+
+            parent->appendRow(QList<QStandardItem*>() << it1 << itStatus);
+        } else {
+            QStandardItem *parent = it1->parent();
+            if(parent == 0)
+                parent = invisibleRootItem();
+            itStatus = parent->child(it1->row(), 1);
+        }
+
+        QString text = stateToString(status.state());
+        if(itStatus->text()!=text) {
+            itStatus->setText(text);
+            itStatus->setIcon(stateToIcon(status.state()));
+        }
+        it1->setData(qVariantFromValue<VcsStatusInfo>(status), VcsStatusInfoRole);
+        return it1->row();
+    }
+}
+
+QStandardItem* VcsFileChangesModel::fileItemForUrl(QStandardItem* parent, const \
QUrl& url) +{
+    for(int i=0; i<parent->rowCount(); i++) {
+        QStandardItem* curr=parent->child(i);
+
+        if(curr->data(VcsStatusInfoRole).value<VcsStatusInfo>().url()==url) {
+            return curr;
+        }
+    }
+
+    return 0;
+}
+
+QList<VcsStatusInfo> VcsFileChangesModel::checkedStatuses(QStandardItem *parent) \
const +{
+    QList<VcsStatusInfo> ret;
+
+    if(!d->allowSelection)
+        return ret;
+
+    for(int i = 0; i < parent->rowCount(); i++) {
+        QStandardItem* item = parent->child(i);
+        if(item->checkState() == Qt::Checked) {
+            ret << statusInfo(item);
+        }
+    }
+
+    return ret;
+}
+
+QList<KUrl> VcsFileChangesModel::checkedUrls(QStandardItem *parent) const
+{
+    QList<KUrl> ret;
+
+    if(!d->allowSelection)
+        return ret;
+
+    for(int i = 0; i < parent->rowCount(); i++) {
+        QStandardItem* item = parent->child(i);
+        if(item->checkState() == Qt::Checked) {
+            ret << statusInfo(item).url();
+        }
+    }
+
+    return ret;
+}
+
+
+}
diff --git a/vcs/models/vcsfilechangesmodel.h b/vcs/models/vcsfilechangesmodel.h
new file mode 100644
index 0000000..af02e80
--- /dev/null
+++ b/vcs/models/vcsfilechangesmodel.h
@@ -0,0 +1,127 @@
+/*  This file is part of KDevelop
+    Copyright 2010 Aleix Pol <aleixpol@kde.org>
+
+    Splitted into separate class
+    Copyright 2011 Andrey Batyiev <batyiev@gmail.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FILECHANGESMODEL_H
+#define FILECHANGESMODEL_H
+
+#include <QStandardItemModel>
+
+#include <vcs/vcsstatusinfo.h>
+
+#include "../vcsexport.h"
+
+class KUrl;
+
+namespace KDevelop
+{
+class VcsStatusInfo;
+
+/**
+ * This class holds and represents information about changes in files.
+ * Also it is possible to provide tree like models by inheriting this class, see \
protected members. + * All stuff should be pulled in by @p updateState.
+ */
+
+class KDEVPLATFORMVCS_EXPORT VcsFileChangesModel : public QStandardItemModel
+{
+    Q_OBJECT
+public:
+    /**
+     * Constructor for class.
+     * @param allowSelection if true, model will show checkboxes on items.
+     */
+    VcsFileChangesModel(QObject *parent, bool allowSelection = false);
+    enum ItemRoles { VcsStatusInfoRole = Qt::UserRole+1 };
+
+    /**
+     * Returns item for particular url.
+     */
+    QStandardItem* fileItemForUrl(const QUrl &url) {
+        return fileItemForUrl(invisibleRootItem(), url);
+    }
+
+    /**
+     * Returns list of currently checked statuses.
+     */
+    QList<VcsStatusInfo> checkedStatuses() const {
+        return checkedStatuses(invisibleRootItem());
+    }
+
+    /**
+     * Returns list of currently checked urls.
+     */
+    QList<KUrl> checkedUrls() const {
+        return checkedUrls(invisibleRootItem());
+    }
+
+
+    /**
+     * Simple helper to get VcsStatusInfo.
+     */
+    static VcsStatusInfo statusInfo(const QModelIndex &i) {
+        return i.data(VcsStatusInfoRole).value<VcsStatusInfo>();
+    }
+
+    /**
+     * Simple helper to get VcsStatusInfo.
+     */
+    static VcsStatusInfo statusInfo(const QStandardItem *item) {
+        return item->data(VcsStatusInfoRole).value<VcsStatusInfo>();
+    }
+
+public slots:
+    /**
+     * Used to post update of status of some file. Any status except UpToDate
+     * and Unknown will update (or add) item representation.
+     */
+    void updateState(const KDevelop::VcsStatusInfo &status) {
+        updateState(invisibleRootItem(), status);
+    }
+
+protected:
+    /**
+     * Post update of status of some file.
+     * @return changed row or -1 if row is deleted
+     */
+    int updateState(QStandardItem *parent, const KDevelop::VcsStatusInfo &status);
+
+    /**
+     * Returns item for particular url.
+     */
+    static QStandardItem* fileItemForUrl(QStandardItem *parent, const QUrl &url);
+
+    /**
+     * Returns list of currently checked statuses.
+     */
+    QList<VcsStatusInfo> checkedStatuses(QStandardItem *parent) const;
+
+    /**
+     * Returns list of currently checked urls.
+     */
+    QList<KUrl> checkedUrls(QStandardItem *parent) const;
+
+private:
+    class VcsFileChangesModelPrivate *const d;
+};
+}
+
+#endif // FILECHANGESMODEL_H
diff --git a/vcs/widgets/vcscommitdialog.cpp b/vcs/widgets/vcscommitdialog.cpp
index fca9e94..607d5aa 100644
--- a/vcs/widgets/vcscommitdialog.cpp
+++ b/vcs/widgets/vcscommitdialog.cpp
@@ -35,6 +35,7 @@
 #include "../interfaces/idistributedversioncontrol.h"
 #include "../interfaces/icentralizedversioncontrol.h"
 #include "../vcsstatusinfo.h"
+#include "../models/vcsfilechangesmodel.h"
 
 #include "ui_vcscommitdialog.h"
 #include <KComponentData>
@@ -46,47 +47,13 @@ namespace KDevelop
 class VcsCommitDialogPrivate
 {
 public:
-
-    VcsCommitDialogPrivate(VcsCommitDialog* dialog)
-        : dlg(dialog)
-    {}
-
-    void insertRow( const QString& state, const KUrl& url,
-                    const KStatefulBrush &foregroundColor = \
                KStatefulBrush(KColorScheme::View, KColorScheme::NormalText),
-                    Qt::CheckState checkstate = Qt::Checked)
-    {
-        QStringList strings;
-        strings << "" << state << \
ICore::self()->projectController()->prettyFileName(url, \
                KDevelop::IProjectController::FormatPlain);
-        QTreeWidgetItem *item = new QTreeWidgetItem( ui.files, strings );
-        item->setData(0, Qt::UserRole, url);
-        item->setForeground(2,  foregroundColor.brush(dlg));
-        item->setCheckState(0, checkstate);
-    }
-
-    QList< KUrl > selection() {
-        if(!m_selection.isEmpty())
-            return m_selection;
-        
-        QList< KUrl > ret;
-        
-        QTreeWidgetItemIterator it( ui.files, QTreeWidgetItemIterator::Checked );
-        for( ; *it; ++it ){
-            QVariant v = (*it)->data(0, Qt::UserRole);
-            Q_ASSERT(v.canConvert<KUrl>());
-            ret << v.value<KUrl>();
-        }
-        
-        return ret;
-    }
-
-    VcsCommitDialog* dlg;
     Ui::VcsCommitDialog ui;
-    QList< KUrl > m_selection;
     IPatchSource* m_patchSource;
+    VcsFileChangesModel* m_model;
 };
 
 VcsCommitDialog::VcsCommitDialog( IPatchSource *patchSource, QWidget *parent )
-    : KDialog( parent ), d(new VcsCommitDialogPrivate(this))
+    : KDialog( parent ), d(new VcsCommitDialogPrivate())
 {
     d->ui.setupUi( mainWidget() );
     QWidget *customWidget = patchSource->customWidget();
@@ -97,9 +64,9 @@ VcsCommitDialog::VcsCommitDialog( IPatchSource *patchSource, \
QWidget *parent )  
     setButtons( KDialog::Ok | KDialog::Cancel );
 
-    d->ui.files->resizeColumnToContents(0);
-    d->ui.files->resizeColumnToContents(1);
     d->m_patchSource = patchSource;
+    d->m_model = new VcsFileChangesModel( this, true );
+    d->ui.files->setModel( d->m_model );
     connect(this, SIGNAL( okClicked() ), SLOT( ok() ) );
     connect(this, SIGNAL( cancelClicked() ), SLOT( cancel() ) );
 }
@@ -116,47 +83,10 @@ void VcsCommitDialog::setRecursive( bool recursive )
 
 void VcsCommitDialog::setCommitCandidates( const QVariant& statuses )
 {
-    KStatefulBrush deletedRed(KColorScheme::View, KColorScheme::NegativeText);
-    KStatefulBrush newGreen(KColorScheme::View, KColorScheme::ActiveText);
-
     foreach( const QVariant &var, statuses.toList() )
     {
         VcsStatusInfo info = qVariantValue<KDevelop::VcsStatusInfo>( var );
-
-        QString state;
-        KStatefulBrush brush(KColorScheme::View, KColorScheme::NormalText);
-        Qt::CheckState checked = Qt::Checked;
-
-        switch( info.state() )
-        {
-            case VcsStatusInfo::ItemAdded:
-                state = i18nc("file was added to versioncontrolsystem", "Added");
-                brush = newGreen;
-                break;
-            case VcsStatusInfo::ItemDeleted:
-                state = i18nc("file was deleted from versioncontrolsystem", \
                "Deleted");
-                brush = deletedRed;
-                break;
-            case VcsStatusInfo::ItemModified:
-                state = i18nc("version controlled file was modified", "Modified");
-                break;
-            case VcsStatusInfo::ItemUnknown:
-                state = i18nc("file is not known to versioncontrolsystem", \
                "Unknown");
-                brush = newGreen;
-                checked = Qt::Unchecked;
-                break;
-            default:
-                break;
-        }
-
-        if(!state.isEmpty())
-        {
-            d->insertRow(state, info.url(), brush, checked);
-        }
-    }
-    if( d->ui.files->topLevelItemCount() == 0 )
-    {
-        reject();
+        d->m_model->updateState( info );
     }
 }
 
@@ -167,7 +97,7 @@ bool VcsCommitDialog::recursive() const
 
 void VcsCommitDialog::ok()
 {
-    if( d->m_patchSource->finishReview(d->selection()) )
+    if( d->m_patchSource->finishReview( d->m_model->checkedUrls() ) )
     {
         deleteLater();
     }
diff --git a/vcs/widgets/vcscommitdialog.ui b/vcs/widgets/vcscommitdialog.ui
index 5f09c95..f32f8a2 100644
--- a/vcs/widgets/vcscommitdialog.ui
+++ b/vcs/widgets/vcscommitdialog.ui
@@ -38,31 +38,13 @@
     </widget>
    </item>
    <item row="2" column="0" colspan="2">
-    <widget class="QTreeWidget" name="files">
-     <property name="windowTitle">
-      <string>Select Files to commit</string>
+    <widget class="QTreeView" name="files">
+     <property name="editTriggers">
+      <set>QAbstractItemView::NoEditTriggers</set>
      </property>
-     <property name="indentation">
-      <number>0</number>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
      </property>
-     <property name="allColumnsShowFocus">
-      <bool>true</bool>
-     </property>
-     <column>
-      <property name="text">
-       <string/>
-      </property>
-     </column>
-     <column>
-      <property name="text">
-       <string>Status</string>
-      </property>
-     </column>
-     <column>
-      <property name="text">
-       <string>Files to commit</string>
-      </property>
-     </column>
     </widget>
    </item>
   </layout>


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic