Browse Source

Fix issue with focus jumping from console to diff

Alexey Edelev 7 years ago
parent
commit
52116bcedc

+ 4 - 2
NiceGit.pro

@@ -29,7 +29,8 @@ SOURCES += \
     tooltipviewmodel.cpp \
     gitconsole.cpp \
     colorhandler.cpp \
-    diffmodel.cpp
+    diffmodel.cpp \
+    settings.cpp
 
 HEADERS += \
     githandler.h \
@@ -55,7 +56,8 @@ HEADERS += \
     tooltipviewmodel.h \
     gitconsole.h \
     colorhandler.h \
-    diffmodel.h
+    diffmodel.h \
+    settings.h
 
 RESOURCES += \
     resources.qrc

+ 42 - 9
githandler.cpp

@@ -1,11 +1,11 @@
 #include "githandler.h"
 
-#include <QDebug>
 #include <QUrl>
 #include <QFileSystemWatcher>
 #include <QGuiApplication>
 #include <QClipboard>
 #include <QtConcurrentRun>
+#include <QDebug>
 #include <qqml.h>
 
 #include <gitrepository.h>
@@ -22,6 +22,7 @@
 #include <taglistmodel.h>
 #include <gitconsole.h>
 #include <graphpoint.h>
+#include <settings.h>
 
 GitHandler::GitHandler() : QObject()
   ,m_repositories(new RepositoryModel(this))
@@ -33,7 +34,7 @@ GitHandler::GitHandler() : QObject()
   ,m_tagList(new TagListModel(this))
   ,m_activeRepoWatcher(new QFileSystemWatcher(this))
   ,m_console(new GitConsole(this))
-{    
+{
     git_libgit2_init();
     connect(&m_diffTask, &QFutureWatcher<GitDiff*>::finished, this, &GitHandler::onDiffReady);
     connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::finished, this, &GitHandler::onGraphReady);
@@ -43,6 +44,8 @@ GitHandler::GitHandler() : QObject()
     connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::canceled, this, &GitHandler::isBusyChanged);
     connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::paused, this, &GitHandler::isBusyChanged);
     connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::resumed, this, &GitHandler::isBusyChanged);
+
+    loadCachedRepos();
 }
 
 GitHandler::~GitHandler()
@@ -50,32 +53,33 @@ GitHandler::~GitHandler()
     git_libgit2_shutdown();
 }
 
-void GitHandler::open(const QUrl &url)
+GitRepository *GitHandler::open(const QUrl &url)
 {
     if(url.isLocalFile()) {
-        open(url.toLocalFile());
+        return open(url.toLocalFile());
     }
+    return nullptr;
 }
 
-void GitHandler::open(const QString &path)
+GitRepository *GitHandler::open(const QString &path)
 {
     qDebug() << "path" << path;
     git_buf root = {0,0,0};
     if(git_repository_discover(&root, path.toUtf8().data(), 0, NULL) != 0) {
         qDebug() << lastError();
-        return;
+        return nullptr;
     }
 
     GitRepository* repo = new GitRepository(QString::fromUtf8(root.ptr, root.size));
-    setActiveRepo(repo);
+    Settings::instance()->add(repo);
     m_repositories->addRepository(repo);
+    return repo;
 }
 
 void GitHandler::activateRepository(int i)
 {
     GitRepository* repo = m_repositories->at(i);
     setActiveRepo(repo);
-    m_repositories->setActiveRepositoryIndex(i);
 }
 
 void GitHandler::setActiveRepo(GitRepository* repo)
@@ -93,11 +97,17 @@ void GitHandler::setActiveRepo(GitRepository* repo)
         m_activeRepoWatcher->removePath(m_activeRepo->root());
 
         disconnect(m_activeRepo, &GitRepository::branchesChanged, this, &GitHandler::updateModels);
-
     }
 
     m_activeRepo = repo;
 
+    connect(m_activeRepoWatcher, &QFileSystemWatcher::directoryChanged, m_activeRepo, &GitRepository::readBranches);
+    connect(m_activeRepoWatcher, &QFileSystemWatcher::directoryChanged, m_activeRepo, &GitRepository::readRemotes);
+    connect(m_activeRepoWatcher, &QFileSystemWatcher::directoryChanged, m_activeRepo, &GitRepository::readTags);
+    connect(m_activeRepoWatcher, &QFileSystemWatcher::directoryChanged, this, &GitHandler::updateModels);
+    connect(m_activeRepo, &GitRepository::branchesChanged, this, &GitHandler::updateModels);
+
+
     ColorHandler::instance().updateColors(m_activeRepo);
     m_constantHead = m_activeRepo->head();
     m_console->setRepository(m_activeRepo);
@@ -105,7 +115,12 @@ void GitHandler::setActiveRepo(GitRepository* repo)
     updateModels();
 
     m_activeRepoWatcher->addPath(m_activeRepo->root());
+
+    qDebug() << "Active repo index: " << m_repositories->indexOf(m_activeRepo);
+    m_repositories->setActiveRepositoryIndex(m_repositories->indexOf(m_activeRepo));
     activeRepoChanged(m_activeRepo);
+
+    Settings::instance()->saveLastRepo(m_activeRepo);
 }
 
 
@@ -235,3 +250,21 @@ void GitHandler::onGraphReady()
     m_commits = CommitModel::fromGraph(m_graph);
     emit commitsChanged(m_commits);
 }
+
+void GitHandler::loadCachedRepos()
+{
+    QString activeRepo = Settings::instance()->loadLastRepo();
+    GitRepository* lastRepo = nullptr;
+
+    QStringList cachedRepos;
+    Settings::instance()->load(cachedRepos);
+
+    foreach (QString repoPath, cachedRepos) {
+        GitRepository* repo = open(repoPath);
+        if(repo->id() == activeRepo) {
+            lastRepo = repo;
+        }
+    }
+
+    setActiveRepo(lastRepo);
+}

+ 3 - 3
githandler.h

@@ -31,8 +31,8 @@ class GitHandler : public QObject
 public:
     GitHandler();
     virtual ~GitHandler();
-    Q_INVOKABLE void open(const QString &path);
-    Q_INVOKABLE void open(const QUrl &url);
+    Q_INVOKABLE GitRepository *open(const QString &path);
+    Q_INVOKABLE GitRepository *open(const QUrl &url);
     Q_INVOKABLE void activateRepository(int i);
 
     Q_INVOKABLE void diff(GitCommit* a, GitCommit* b);
@@ -117,6 +117,7 @@ private:
 
     static CommitGraph* updateGraph(const GitOid& head, const BranchContainer &branches);
     void onGraphReady();
+    void loadCachedRepos();
 
     RepositoryModel* m_repositories;
     CommitModel* m_commits;
@@ -130,7 +131,6 @@ private:
     GitOid m_constantHead;
     QFutureWatcher<GitDiff*> m_diffTask;
     QFutureWatcher<CommitGraph*> m_graphTask;
-
     bool m_isBusy;
 };
 

+ 10 - 8
gitrepository.cpp

@@ -3,6 +3,7 @@
 #include <QDebug>
 #include <QFileInfo>
 #include <QDir>
+#include <QCryptographicHash>
 
 #include <gitbranch.h>
 #include <gitcommit.h>
@@ -12,7 +13,6 @@
 
 #include <git2.h>
 
-
 GitRepository::GitRepository(const QString& root) : QObject(nullptr)
 {
     if(git_repository_open(&m_raw, root.toUtf8().data()) != 0) {
@@ -23,7 +23,7 @@ GitRepository::GitRepository(const QString& root) : QObject(nullptr)
 
     m_root = root;
     m_path = git_repository_workdir(m_raw);
-    m_name = m_path;//TODO: replace with Human readable name
+    m_name = m_path.split("/", QString::SkipEmptyParts).last();
     qDebug() << "New repo:" << m_name << m_root << m_path;
     readBranches();
     readTags();
@@ -50,8 +50,7 @@ void GitRepository::readBranches()
     git_branch_t branchType;
     git_branch_iterator* iter;
     git_branch_iterator_new(&iter, m_raw, GIT_BRANCH_ALL);
-    while(git_branch_next(&branchRef, &branchType, iter) == 0)
-    {
+    while(git_branch_next(&branchRef, &branchType, iter) == 0) {
         GitBranch* branch = new GitBranch(branchRef, branchType, this);
         m_branches.insert(branch->fullName(), QPointer<GitBranch>(branch));
         qDebug() << branch->fullName();
@@ -63,8 +62,7 @@ void GitRepository::readBranches()
 void GitRepository::readTags()
 {
     git_tag_foreach(raw(),
-                [](const char *name, git_oid *oid, void *payload) -> int
-    {
+                [](const char *name, git_oid *oid, void *payload) -> int {
         Q_UNUSED(payload)
         Q_UNUSED(name)
 
@@ -119,8 +117,7 @@ void GitRepository::checkout(QObject* object)
             const git_diff_file *baseline,
             const git_diff_file *target,
             const git_diff_file *workdir,
-            void *payload) -> int
-    {
+            void *payload) -> int {
         //TODO: make popup with progressbar
 //        qDebug() << "path:" << path;
 //        switch (why) {
@@ -202,3 +199,8 @@ void GitRepository::updateHead()
     qDebug() << "Repo head" << m_head.toString();
 }
 
+
+QString GitRepository::id() const
+{
+    return QCryptographicHash::hash(name().toUtf8() + path().toUtf8(), QCryptographicHash::Sha1).toHex();
+}

+ 4 - 0
gitrepository.h

@@ -28,6 +28,7 @@ class GitRepository : public QObject
     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
     Q_PROPERTY(QString path READ path NOTIFY rootChanged)
     Q_PROPERTY(GitOid head READ head WRITE setHead NOTIFY headChanged)
+    Q_PROPERTY(QString id READ id NOTIFY rootChanged)
 
 public:
     GitRepository(const QString &root);
@@ -70,12 +71,15 @@ public:
         return m_head;
     }
 
+    QString id() const;
+
     Q_INVOKABLE bool isHead(const GitOid& oid) const {
         return m_head == oid;
     }
 
     Q_INVOKABLE void checkout(QObject* object);
 
+
 public slots:
     void setRoot(QString root) {
         if (m_root == root)

BIN
images/question-mark-4-24.png


BIN
images/question-mark-4-24_active.png


BIN
images/x-mark-3-48.png


BIN
images/x-mark-3-48_active.png


+ 0 - 1
main.cpp

@@ -59,7 +59,6 @@ int main(int argc, char *argv[])
     });
 
     GitHandler handler;
-    handler.open("/home/semlanik/Projects/HCAT/hmi_hcat/demo/default/HCAT/");
     view.rootContext()->setContextProperty("_handler", &handler);
     view.setSource(QUrl("qrc:/qml/MainView.qml"));
     view.setResizeMode(QQuickView::SizeRootObjectToView);

+ 14 - 8
qml/CommitInfo.qml

@@ -2,6 +2,7 @@ import QtQuick 2.0
 
 Item {
     id: root
+    property QtObject model: null
     state: "closed"
     clip: true
     states: [
@@ -21,15 +22,20 @@ Item {
         },
         State {
             name: "hidden"
-            when: !root.visible
+            when: !root.visible || model == null
             PropertyChanges {
                 target: root
                 height: 0
             }
         }
-
     ]
 
+    onModelChanged:{
+        if(model != null) {
+            root.state = "closed"
+        }
+    }
+
     transitions: Transition {
         NumberAnimation {
             properties: "height"
@@ -42,27 +48,27 @@ Item {
         width: parent.width
         CommitInfoLine {
             field: qsTr("Time")
-            value: commit ? commit.time : ""
+            value: model ? model.time : ""
         }
 
         CommitInfoLine {
             field: qsTr("Author")
-            value: commit ? commit.author : ""
+            value: model ? model.author : ""
         }
 
         CommitInfoLine {
             field: qsTr("Email")
-            value: commit ? commit.email : ""
+            value: model ? model.email : ""
         }
 
         CommitInfoLine {
             field: qsTr("Summary")
-            value: commit ? commit.summary : ""
+            value: model ? model.summary : ""
         }
     }
     Image {
         id: merge
-        visible: commit ? commit.isMerge : false
+        visible: model ? model.isMerge : false
         source: "qrc:///images/flow-merge.png"
         anchors.right: shortInfo.right
         anchors.rightMargin: 5
@@ -90,7 +96,7 @@ Item {
             wrapMode: Text.WordWrap
             width: parent.width
             height: contentHeight
-            text: commit ? commit.message : ""
+            text: model ? model.message : ""
         }
 
         Rectangle {

+ 4 - 3
qml/CommitPlane.qml

@@ -24,11 +24,11 @@ Item {
 
     CommitInfo {
         id: commitInfo
+        model: root.commit
         anchors.top: parent.top
         anchors.left: parent.left
         anchors.leftMargin: 20
         width: d.commitInfoWidth
-        visible: commit != null
     }
 
     DiffFiles {
@@ -99,6 +99,7 @@ Item {
                 font.pointSize: 12
                 selectByMouse: true
                 readOnly: true
+                activeFocusOnPress: false
             }
         }
     }
@@ -136,11 +137,11 @@ Item {
         anchors.fill: diffViewport
         active: fileDiff.text == ""
         visible: diff != null
-        text: "Select file on side panel"
+        text: qsTr("Select file on side panel")
     }
 
     AreaPlaceholder {
         active: diff == null
-        text: "Select commit in graph"
+        text: qsTr("Select commit in graph")
     }
 }

+ 8 - 3
qml/MainView.qml

@@ -79,9 +79,6 @@ FocusScope {
             property: "diff"
             value: _handler.activeDiff
         }
-
-//        visible: diff != null
-//        opacity: diff != null ? 1.0 : 0.0
     }
 
     Rectangle {
@@ -107,6 +104,14 @@ FocusScope {
         anchors.bottom: parent.bottom
     }
 
+    Connections {
+        target: _handler
+        onActiveRepoChanged: {
+            commitPlane.diff = null
+            commitPlane.commit = null
+        }
+    }
+
     Keys.onPressed: {
         event.accepted = true
         switch(event.key) {

+ 7 - 0
qml/Separator.qml

@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Rectangle {
+    width: 1
+    height: parent.height/2
+    color: "#dddddd"
+}

+ 73 - 27
qml/TopBar.qml

@@ -10,56 +10,102 @@ Item {
     signal closeClicked()
     property alias closeVisible: closeControl.visible
     Row {
+        anchors.left: parent.left
+        anchors.leftMargin: 10
         spacing: 10
-        height: 50
+        height: 40
+        Text {
+            font.weight: Font.Bold
+            anchors.verticalCenter: parent.verticalCenter
+            text: qsTr("Active projects") + ":"
+        }
+
         ComboBox {
             id: repositories
+            anchors.verticalCenter: parent.verticalCenter
             width: 400
             model: _handler.repositories
             textRole: "name"
             onActivated: {
                 _handler.activateRepository(index)
             }
+            currentIndex: _handler.repositories.activeRepositoryIndex
+            style: ComboBoxStyle {
+                font.weight:Font.Bold
+            }
         }
 
-        Text {
-            text: "Active repository" + repoOpenDialog.fileUrl
+        Separator {
+            anchors.verticalCenter: parent.verticalCenter
         }
+
         Button {
-            text: "Choose..."
+            anchors.verticalCenter: parent.verticalCenter
+            text: qsTr("Add...")
             onClicked: repoOpenDialog.open()
         }
-
-        Text {
-            text: _handler.activeRepo.name
-        }
-
-        FileDialog {
-            id: repoOpenDialog
-            folder: "."
-            selectFolder: true
-            selectMultiple: false
-            onAccepted: {
-                //TODO: repo open is not available
-                _handler.open(repoOpenDialog.fileUrl)
-            }
-        }
-
     }
 
-    Button {
-        id: closeControl
+    Row {
         anchors.right: parent.right
         anchors.top: parent.top
         anchors.topMargin: 10
         anchors.rightMargin: 10
-        style: ButtonStyle {
-            background: Image {
-                source: control.pressed ? "qrc:///images/x-mark-3-24_active.png" : "qrc:///images/x-mark-3-24.png"
+        spacing: 10
+        Button {
+            id: closeControl
+            style: ButtonStyle {
+                background: Image {
+                    source: control.pressed ? "qrc:///images/x-mark-3-24_active.png" : "qrc:///images/x-mark-3-24.png"
+                }
+            }
+            onClicked: {
+                root.closeClicked()
+            }
+        }
+        Button {
+            id: help
+            style: ButtonStyle {
+                background: Image {
+                    source: control.pressed ? "qrc:///images/question-mark-4-24_active.png" : "qrc:///images/question-mark-4-24.png"
+                }
+            }
+            onClicked: {
+                helpDialog.open()
             }
         }
-        onClicked: {
-            root.closeClicked()
+    }
+
+    FileDialog {
+        id: repoOpenDialog
+        folder: "."
+        selectFolder: true
+        selectMultiple: false
+        onAccepted: {
+            _handler.setActiveRepo(_handler.open(repoOpenDialog.fileUrl))
+        }
+    }
+
+    Dialog {
+        id: helpDialog
+        title: qsTr("About")
+        modality: Qt.NonModal
+        contentItem: Item {
+            implicitWidth: 400
+            implicitHeight: 200
+            Text {
+                anchors.left: parent.left
+                anchors.leftMargin: 8
+                anchors.right: parent.right
+                anchors.rightMargin: 8
+                anchors.horizontalCenter: parent
+                wrapMode: Text.WordWrap
+                font.pointSize: 12
+                textFormat: Text.RichText
+                text:"<p><b>CuteGit</b> is free opensource software. You're free to use and modify it in terms of GPLv3 license.<br/>" +
+                     "You can support project by contributing your ideas and code to CuteGit repository.</p>" +
+                     "<p><b>Autor:</b> Alexey Edelev aka semlanik</p>"
+            }
         }
     }
 }

+ 3 - 2
resources.qrc

@@ -5,8 +5,6 @@
         <file>qml/Graph.qml</file>
         <file>qml/CommitList.qml</file>
         <file>qml/DiffFiles.qml</file>
-        <file>images/x-mark-3-48.png</file>
-        <file>images/x-mark-3-48_active.png</file>
         <file>images/x-mark-3-24_active.png</file>
         <file>images/x-mark-3-24.png</file>
         <file>qml/TopBar.qml</file>
@@ -52,5 +50,8 @@
         <file>images/erase-24_active.png</file>
         <file>images/flow-merge.png</file>
         <file>images/flow-merge-16.png</file>
+        <file>qml/Separator.qml</file>
+        <file>images/question-mark-4-24.png</file>
+        <file>images/question-mark-4-24_active.png</file>
     </qresource>
 </RCC>

+ 63 - 0
settings.cpp

@@ -0,0 +1,63 @@
+#include "settings.h"
+
+#include "gitrepository.h"
+#include <QFileInfo>
+#include <QCryptographicHash>
+
+namespace {
+    const QString GeneralGroupKey = "General";
+    const QString RepoNameKey = "Name";
+    const QString RepoPathKey = "Path";
+    const QString LastRepoKey = "LastRepo";
+}
+
+Settings::Settings() : QObject()
+  ,m_settings("org.semlanik",
+              "NiceGit")
+{
+}
+
+void Settings::load(QStringList& repos)
+{
+    QStringList groups = m_settings.childGroups();
+
+    foreach (QString group, groups) {
+        m_settings.beginGroup(group);
+        QString path = m_settings.value(RepoPathKey).toString();
+        QFileInfo fileInfo(path);
+        if(!fileInfo.exists(path) || !fileInfo.isDir()) {
+            m_settings.remove("");
+        } else {
+            repos.append(path);
+        }
+        m_settings.endGroup();
+    }
+}
+
+void Settings::add(GitRepository* repo)
+{
+    if(repo == nullptr) {
+        return;
+    }
+
+    m_settings.beginGroup(repo->id());
+    m_settings.setValue(RepoNameKey, repo->name());
+    m_settings.setValue(RepoPathKey, repo->path());
+    m_settings.endGroup();
+}
+
+void Settings::saveLastRepo(GitRepository* repo)
+{
+    m_settings.beginGroup(GeneralGroupKey);
+    m_settings.setValue(LastRepoKey, repo->id());
+    m_settings.endGroup();
+}
+
+QString Settings::loadLastRepo()
+{
+    m_settings.beginGroup(GeneralGroupKey);
+    QString result = m_settings.value(LastRepoKey).toString();
+    m_settings.endGroup();
+
+    return result;
+}

+ 32 - 0
settings.h

@@ -0,0 +1,32 @@
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <QObject>
+#include <QSettings>
+
+class GitRepository;
+
+class Settings Q_DECL_FINAL : public QObject
+{
+    Q_OBJECT
+public:
+    static Settings* instance() {
+        static Settings settings;
+        return &settings;
+    }
+
+    void load(QStringList& repos);
+    void add(GitRepository* repo);
+
+    void saveLastRepo(GitRepository* activeRepoId);
+    QString loadLastRepo();
+
+private:
+    Settings();
+    ~Settings(){}
+    Q_DISABLE_COPY(Settings)
+
+    QSettings m_settings;
+};
+
+#endif // SETTINGS_H

+ 6 - 1
universallistmodel.h

@@ -87,10 +87,15 @@ public:
         endResetModel();
     }
 
-    T* at(int i) {
+    T* at(int i) const {
         return m_container.at(i);
     }
 
+    int indexOf(T* value) const {
+        return m_container.indexOf(value);
+    }
+
+
 protected:
     void clear() {
 //TODO: need to verify if wee really should cleanup these commits.