ADDED: Git integration support
Adds support for project-based git integration, branch support, commit, revert and updates Fixes https://gitlab.com/kicad/code/kicad/issues/10441
This commit is contained in:
parent
8f96009fe5
commit
d99641be40
|
@ -746,6 +746,12 @@ find_package(ZLIB REQUIRED)
|
|||
#
|
||||
find_package( CURL REQUIRED )
|
||||
|
||||
#
|
||||
# Find libssl, required
|
||||
#
|
||||
find_package( OpenSSL REQUIRED )
|
||||
include_directories( SYSTEM ${OPENSSL_INCLUDE_DIR} )
|
||||
|
||||
#
|
||||
# Find Cairo library, required
|
||||
#
|
||||
|
@ -755,6 +761,12 @@ include_directories( SYSTEM ${CAIRO_INCLUDE_DIR} )
|
|||
find_package( Pixman 0.30 REQUIRED )
|
||||
include_directories( SYSTEM ${PIXMAN_INCLUDE_DIR} )
|
||||
|
||||
# Find libgit2, required
|
||||
find_package( libgit2 REQUIRED )
|
||||
|
||||
# Set include directories for libgit
|
||||
include_directories(${LIBGIT2_INCLUDE_DIRS})
|
||||
|
||||
#
|
||||
# Find Boost headers and libraries, required.
|
||||
set( BOOST_REQUESTED_COMPONENTS locale ) # locale is required by nanoodbc/database libraries
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# SPDX-FileCopyrightText: 2014 Dan Leinir Turthra Jensen <admin@leinir.dk
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
# - Try to find the libgit2 library
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBGIT2_FOUND - System has libgit2
|
||||
# LIBGIT2_INCLUDE_DIR - The libgit2 include directory
|
||||
# LIBGIT2_LIBRARIES - The libraries needed to use libgit2
|
||||
# LIBGIT2_DEFINITIONS - Compiler switches required for using libgit2
|
||||
|
||||
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
find_package(PkgConfig)
|
||||
pkg_search_module(PC_LIBGIT2 libgit2)
|
||||
|
||||
set(LIBGIT2_DEFINITIONS ${PC_LIBGIT2_CFLAGS_OTHER})
|
||||
|
||||
find_path(LIBGIT2_INCLUDE_DIR NAMES git2.h
|
||||
HINTS
|
||||
${PC_LIBGIT2_INCLUDEDIR}
|
||||
${PC_LIBGIT2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(LIBGIT2_LIBRARIES NAMES git2
|
||||
HINTS
|
||||
${PC_LIBGIT2_LIBDIR}
|
||||
${PC_LIBGIT2_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(libgit2 DEFAULT_MSG LIBGIT2_LIBRARIES LIBGIT2_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(LIBGIT2_INCLUDE_DIR LIBGIT2_LIBRARIES)
|
|
@ -131,6 +131,8 @@ target_link_libraries( kicommon
|
|||
fmt::fmt
|
||||
CURL::libcurl
|
||||
${wxWidgets_LIBRARIES}
|
||||
${LIBGIT2_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
|
||||
# needed by kiid to allow linking for Boost for the UUID against bcrypt (msys2 only)
|
||||
${EXTRA_LIBS}
|
||||
|
@ -195,7 +197,19 @@ set( COMMON_ABOUT_DLG_SRCS
|
|||
dialog_about/dialog_about_base.cpp
|
||||
)
|
||||
|
||||
set( COMMON_GIT_DLG_SRCS
|
||||
dialogs/git/dialog_git_commit.cpp
|
||||
dialogs/git/dialog_git_switch.cpp
|
||||
dialogs/git/dialog_git_auth.cpp
|
||||
dialogs/git/dialog_git_repository.cpp
|
||||
dialogs/git/dialog_git_repository_base.cpp
|
||||
dialogs/git/panel_git_repos.cpp
|
||||
dialogs/git/panel_git_repos_base.cpp
|
||||
|
||||
)
|
||||
|
||||
set( COMMON_DLG_SRCS
|
||||
${COMMON_GIT_DLG_SRCS}
|
||||
dialogs/dialog_assign_netclass.cpp
|
||||
dialogs/dialog_assign_netclass_base.cpp
|
||||
dialogs/dialog_book_reporter.cpp
|
||||
|
@ -390,6 +404,20 @@ set( COMMON_IMPORT_GFX_SRCS
|
|||
import_gfx/svg_import_plugin.cpp
|
||||
)
|
||||
|
||||
set( COMMON_GIT_SRCS
|
||||
git/git_add_to_index_handler.cpp
|
||||
git/git_clone_handler.cpp
|
||||
git/git_commit_handler.cpp
|
||||
git/git_pull_handler.cpp
|
||||
git/git_push_handler.cpp
|
||||
git/git_remove_from_index_handler.cpp
|
||||
git/git_resolve_conflict_handler.cpp
|
||||
git/git_revert_handler.cpp
|
||||
git/git_sync_handler.cpp
|
||||
git/kicad_git_common.cpp
|
||||
git/kicad_git_errors.cpp
|
||||
)
|
||||
|
||||
set( COMMON_SRCS
|
||||
${LIB_KICAD_SRCS}
|
||||
${COMMON_ABOUT_DLG_SRCS}
|
||||
|
@ -405,6 +433,7 @@ set( COMMON_SRCS
|
|||
${PLUGINS_EASYEDAPRO_SRCS}
|
||||
${FONT_SRCS}
|
||||
${COMMON_IMPORT_GFX_SRCS}
|
||||
${COMMON_GIT_SRCS}
|
||||
jobs/job_dispatcher.cpp
|
||||
background_jobs_monitor.cpp
|
||||
base_screen.cpp
|
||||
|
|
|
@ -215,6 +215,8 @@ static const wxChar UseClipper2[] = wxT( "UseClipper2" );
|
|||
|
||||
static const wxChar EnableGenerators[] = wxT( "EnableGenerators" );
|
||||
|
||||
static const wxChar EnableGit[] = wxT( "EnableGit" );
|
||||
|
||||
/**
|
||||
* The time in milliseconds to wait before displaying a disambiguation menu.
|
||||
*/
|
||||
|
@ -345,6 +347,7 @@ ADVANCED_CFG::ADVANCED_CFG()
|
|||
m_ShowRepairSchematic = false;
|
||||
m_ShowPropertiesPanel = false;
|
||||
m_EnableGenerators = false;
|
||||
m_EnableGit = false;
|
||||
|
||||
m_3DRT_BevelHeight_um = 30;
|
||||
m_3DRT_BevelExtentFactor = 1.0 / 16.0;
|
||||
|
@ -518,6 +521,9 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
|
|||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableGenerators,
|
||||
&m_EnableGenerators, m_EnableGenerators ) );
|
||||
|
||||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableGit,
|
||||
&m_EnableGit, m_EnableGit ) );
|
||||
|
||||
|
||||
|
||||
// Special case for trace mask setting...we just grab them and set them immediately
|
||||
|
|
|
@ -30,6 +30,13 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
|
|||
aBitmapInfoCache[BITMAPS::e_48].emplace_back( BITMAPS::e_48, wxT( "e_48_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::e_96].emplace_back( BITMAPS::e_96, wxT( "e_96_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::e_192].emplace_back( BITMAPS::e_192, wxT( "e_192_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_add].emplace_back( BITMAPS::git_add, wxT( "git_add_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_changed_ahead].emplace_back( BITMAPS::git_changed_ahead, wxT( "git_changed_ahead_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_conflict].emplace_back( BITMAPS::git_conflict, wxT( "git_conflict_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_delete].emplace_back( BITMAPS::git_delete, wxT( "git_delete_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_good_check].emplace_back( BITMAPS::git_good_check, wxT( "git_good_check_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_modified].emplace_back( BITMAPS::git_modified, wxT( "git_modified_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_out_of_date].emplace_back( BITMAPS::git_out_of_date, wxT( "git_out_of_date_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component_16].emplace_back( BITMAPS::icon_bitmap2component_16, wxT( "icon_bitmap2component_16_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_eeschema_16].emplace_back( BITMAPS::icon_eeschema_16, wxT( "icon_eeschema_16_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_gerbview_16].emplace_back( BITMAPS::icon_gerbview_16, wxT( "icon_gerbview_16_16.png" ), 16, wxT( "light" ) );
|
||||
|
@ -101,6 +108,13 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
|
|||
aBitmapInfoCache[BITMAPS::visibility].emplace_back( BITMAPS::visibility, wxT( "visibility_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::visibility_off].emplace_back( BITMAPS::visibility_off, wxT( "visibility_off_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::www].emplace_back( BITMAPS::www, wxT( "www_16.png" ), 16, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_add].emplace_back( BITMAPS::git_add, wxT( "git_add_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_changed_ahead].emplace_back( BITMAPS::git_changed_ahead, wxT( "git_changed_ahead_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_conflict].emplace_back( BITMAPS::git_conflict, wxT( "git_conflict_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_delete].emplace_back( BITMAPS::git_delete, wxT( "git_delete_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_good_check].emplace_back( BITMAPS::git_good_check, wxT( "git_good_check_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_modified].emplace_back( BITMAPS::git_modified, wxT( "git_modified_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::git_out_of_date].emplace_back( BITMAPS::git_out_of_date, wxT( "git_out_of_date_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component_16].emplace_back( BITMAPS::icon_bitmap2component_16, wxT( "icon_bitmap2component_16_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_eeschema_16].emplace_back( BITMAPS::icon_eeschema_16, wxT( "icon_eeschema_16_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_gerbview_16].emplace_back( BITMAPS::icon_gerbview_16, wxT( "icon_gerbview_16_dark_16.png" ), 16, wxT( "dark" ) );
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "dialog_git_auth.h"
|
||||
|
||||
DIALOG_GIT_AUTH::DIALOG_GIT_AUTH(wxWindow* parent)
|
||||
: DIALOG_SHIM(parent, wxID_ANY, _("Connection"), wxDefaultPosition, wxSize(400, 300))
|
||||
{
|
||||
CreateControls();
|
||||
Centre();
|
||||
}
|
||||
|
||||
DIALOG_GIT_AUTH::~DIALOG_GIT_AUTH()
|
||||
{
|
||||
}
|
||||
|
||||
void DIALOG_GIT_AUTH::CreateControls()
|
||||
{
|
||||
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
this->SetSizer(mainSizer);
|
||||
|
||||
m_NameTextCtrl = new wxTextCtrl(this, wxID_ANY);
|
||||
m_UrlTextCtrl = new wxTextCtrl(this, wxID_ANY);
|
||||
m_AuthChoice = new wxChoice(this, wxID_ANY);
|
||||
m_AuthChoice->Append(_("Basic"));
|
||||
m_AuthChoice->Append(_("SSH"));
|
||||
m_UserNameTextCtrl = new wxTextCtrl(this, wxID_ANY);
|
||||
m_PasswordTextCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD);
|
||||
m_PublicKeyPicker = new wxFilePickerCtrl(this, wxID_ANY);
|
||||
m_PublicKeyPicker->Hide();
|
||||
|
||||
m_TestButton = new wxButton(this, wxID_ANY, _("Test"));
|
||||
m_OkButton = new wxButton(this, wxID_OK, _("OK"));
|
||||
m_CancelButton = new wxButton(this, wxID_CANCEL, _("Cancel"));
|
||||
|
||||
mainSizer->Add(new wxStaticText(this, wxID_ANY, _("Name")), 0, wxALL, 10);
|
||||
mainSizer->Add(m_NameTextCtrl, 0, wxEXPAND | wxALL, 10);
|
||||
mainSizer->Add(new wxStaticText(this, wxID_ANY, _("Url")), 0, wxALL, 10);
|
||||
mainSizer->Add(m_UrlTextCtrl, 0, wxEXPAND | wxALL, 10);
|
||||
mainSizer->Add(new wxStaticText(this, wxID_ANY, _("Authentication")), 0, wxALL, 10);
|
||||
mainSizer->Add(m_AuthChoice, 0, wxEXPAND | wxALL, 10);
|
||||
mainSizer->Add(new wxStaticText(this, wxID_ANY, _("User Name")), 0, wxALL, 10);
|
||||
mainSizer->Add(m_UserNameTextCtrl, 0, wxEXPAND | wxALL, 10);
|
||||
mainSizer->Add(new wxStaticText(this, wxID_ANY, _("Password")), 0, wxALL, 10);
|
||||
mainSizer->Add(m_PasswordTextCtrl, 0, wxEXPAND | wxALL, 10);
|
||||
mainSizer->Add(m_PublicKeyPicker, 0, wxEXPAND | wxALL, 10);
|
||||
|
||||
|
||||
wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttonSizer->Add(m_TestButton, 1, wxALL, 10);
|
||||
buttonSizer->Add(m_OkButton, 1, wxALL, 10);
|
||||
buttonSizer->Add(m_CancelButton, 1, wxALL, 10);
|
||||
mainSizer->Add(buttonSizer, 0, wxALIGN_RIGHT);
|
||||
|
||||
mainSizer->Layout();
|
||||
|
||||
// Bind event for authentication method choice change
|
||||
m_AuthChoice->Bind(wxEVT_CHOICE, &DIALOG_GIT_AUTH::onAuthChoiceChanged, this);
|
||||
m_TestButton->Bind(wxEVT_BUTTON, &DIALOG_GIT_AUTH::onTestClick, this );
|
||||
}
|
||||
|
||||
void DIALOG_GIT_AUTH::onAuthChoiceChanged(wxCommandEvent& event)
|
||||
{
|
||||
if (m_AuthChoice->GetStringSelection() == "SSH")
|
||||
{
|
||||
m_PasswordTextCtrl->Hide();
|
||||
m_PublicKeyPicker->Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PasswordTextCtrl->Show();
|
||||
m_PublicKeyPicker->Hide();
|
||||
}
|
||||
|
||||
Layout(); // Re-arrange the controls
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_REPOSITORY_DIALOG_H
|
||||
#define GIT_REPOSITORY_DIALOG_H
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/filepicker.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include <dialog_shim.h>
|
||||
|
||||
class DIALOG_GIT_AUTH : public DIALOG_SHIM
|
||||
{
|
||||
public:
|
||||
DIALOG_GIT_AUTH( wxWindow* parent );
|
||||
virtual ~DIALOG_GIT_AUTH();
|
||||
|
||||
private:
|
||||
void CreateControls();
|
||||
void onAuthChoiceChanged( wxCommandEvent& event );
|
||||
void onTestClick( wxCommandEvent& aEvent );
|
||||
void onOKClick( wxCommandEvent& aEvent );
|
||||
void onCancelClick( wxCommandEvent& aEvent );
|
||||
|
||||
wxTextCtrl* m_NameTextCtrl;
|
||||
wxTextCtrl* m_UrlTextCtrl;
|
||||
wxChoice* m_AuthChoice;
|
||||
wxTextCtrl* m_UserNameTextCtrl;
|
||||
wxTextCtrl* m_PasswordTextCtrl;
|
||||
wxButton* m_TestButton;
|
||||
wxButton* m_OkButton;
|
||||
wxButton* m_CancelButton;
|
||||
wxFilePickerCtrl* m_PublicKeyPicker;
|
||||
};
|
||||
|
||||
#endif // GIT_REPOSITORY_DIALOG_H
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "dialog_git_commit.h"
|
||||
|
||||
#include <bitmaps/bitmaps_list.h>
|
||||
#include <bitmaps/bitmap_types.h>
|
||||
#include <git/kicad_git_common.h>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
DIALOG_GIT_COMMIT::DIALOG_GIT_COMMIT( wxWindow* parent, git_repository* repo,
|
||||
const wxString& defaultAuthorName,
|
||||
const wxString& defaultAuthorEmail,
|
||||
const std::map<wxString, int>& filesToCommit ) :
|
||||
DIALOG_SHIM( parent, wxID_ANY, "Commit Changes" )
|
||||
{
|
||||
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
|
||||
// List Control for files to commit
|
||||
m_listCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxLC_REPORT | wxLC_SINGLE_SEL );
|
||||
|
||||
// Set up columns
|
||||
m_listCtrl->EnableCheckBoxes();
|
||||
m_listCtrl->AppendColumn( "Filename" );
|
||||
m_listCtrl->AppendColumn( "Placeholder" );
|
||||
|
||||
// Set column widths
|
||||
m_listCtrl->SetColumnWidth(0, 200);
|
||||
m_listCtrl->SetColumnWidth(1, 200);
|
||||
|
||||
// Set up image list for icons
|
||||
wxImageList* imageList = new wxImageList( 16, 16, true,
|
||||
static_cast<int>( KIGIT_COMMON::GIT_STATUS::GIT_STATUS_LAST ) );
|
||||
|
||||
imageList->Add( KiBitmap( BITMAPS::git_good_check ) ); // PLACEHOLDER
|
||||
imageList->Add( KiBitmap( BITMAPS::git_good_check ) ); // GIT_STATUS_CURRENT
|
||||
imageList->Add( KiBitmap( BITMAPS::git_modified ) ); // GIT_STATUS_MODIFIED
|
||||
imageList->Add( KiBitmap( BITMAPS::git_add ) ); // GIT_STATUS_ADDED
|
||||
imageList->Add( KiBitmap( BITMAPS::git_delete ) ); // GIT_STATUS_DELETED
|
||||
imageList->Add( KiBitmap( BITMAPS::git_out_of_date ) ); // GIT_STATUS_BEHIND
|
||||
imageList->Add( KiBitmap( BITMAPS::git_changed_ahead ) );// GIT_STATUS_AHEAD
|
||||
imageList->Add( KiBitmap( BITMAPS::git_conflict ) ); // GIT_STATUS_CONFLICTED
|
||||
|
||||
// Assign the image list to the list control
|
||||
m_listCtrl->SetImageList(imageList, wxIMAGE_LIST_SMALL);
|
||||
|
||||
// Populate list control with items
|
||||
for ( auto& [filename, status] : filesToCommit )
|
||||
{
|
||||
int i = m_listCtrl->GetItemCount();
|
||||
m_listCtrl->InsertItem(i, filename );
|
||||
|
||||
if( status & ( GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_NEW ) )
|
||||
{
|
||||
m_listCtrl->SetItem( i, 1, "New" );
|
||||
m_listCtrl->SetItemImage(i, static_cast<int>( KIGIT_COMMON::GIT_STATUS::GIT_STATUS_ADDED ) );
|
||||
}
|
||||
else if( status & ( GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED ) )
|
||||
{
|
||||
m_listCtrl->SetItem( i, 1, "Modified" );
|
||||
m_listCtrl->SetItemImage(i, static_cast<int>( KIGIT_COMMON::GIT_STATUS::GIT_STATUS_MODIFIED ) );
|
||||
}
|
||||
else if( status & ( GIT_STATUS_INDEX_DELETED | GIT_STATUS_WT_DELETED ) )
|
||||
{
|
||||
m_listCtrl->SetItem( i, 1, "Deleted" );
|
||||
m_listCtrl->SetItemImage(i, static_cast<int>( KIGIT_COMMON::GIT_STATUS::GIT_STATUS_DELETED ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" Unknown status: %d\n", status );
|
||||
}
|
||||
}
|
||||
|
||||
sizer->Add(m_listCtrl, 1, wxEXPAND | wxALL, 5);
|
||||
|
||||
// Commit Message Text Control
|
||||
wxStaticText* commitMessageLabel = new wxStaticText( this, wxID_ANY, _( "Commit Message:" ) );
|
||||
m_commitMessageTextCtrl =
|
||||
new wxTextCtrl( this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE );
|
||||
sizer->Add( commitMessageLabel, 0, wxALL, 5 );
|
||||
sizer->Add( m_commitMessageTextCtrl, 1, wxEXPAND | wxALL, 5 );
|
||||
|
||||
// Author Name and Email Text Control
|
||||
wxStaticText* authorLabel = new wxStaticText( this, wxID_ANY, _( "Author:" ) );
|
||||
wxString defaultAuthor = defaultAuthorName + " <" + defaultAuthorEmail + ">";
|
||||
m_authorTextCtrl =
|
||||
new wxTextCtrl( this, wxID_ANY, defaultAuthor, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
sizer->Add( authorLabel, 0, wxALL, 5 );
|
||||
sizer->Add( m_authorTextCtrl, 0, wxEXPAND | wxALL, 5 );
|
||||
|
||||
// OK and Cancel Buttons
|
||||
|
||||
wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
|
||||
|
||||
m_okButton = new wxButton( this, wxID_OK, _( "OK" ) );
|
||||
wxButton* cancelButton = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
|
||||
buttonSizer->Add( cancelButton, 0, wxALL, 5 );
|
||||
buttonSizer->Add( m_okButton, 0, wxALL, 5 );
|
||||
buttonSizer->Realize();
|
||||
|
||||
sizer->Add( buttonSizer, 0, wxALIGN_RIGHT | wxALL, 5 );
|
||||
|
||||
SetSizerAndFit( sizer );
|
||||
|
||||
SetupStandardButtons( { { wxID_OK, _( "C&ommit" ) } } );
|
||||
|
||||
// Bind events
|
||||
Bind( wxEVT_TEXT, &DIALOG_GIT_COMMIT::OnTextChanged, this, m_commitMessageTextCtrl->GetId() );
|
||||
|
||||
// Set the repository and defaults
|
||||
m_repo = repo;
|
||||
m_defaultAuthorName = defaultAuthorName;
|
||||
m_defaultAuthorEmail = defaultAuthorEmail;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_COMMIT::OnTextChanged( wxCommandEvent& aEvent )
|
||||
{
|
||||
if( m_commitMessageTextCtrl->GetValue().IsEmpty() )
|
||||
{
|
||||
m_okButton->Disable();
|
||||
m_okButton->SetToolTip( _( "Commit message cannot be empty" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_okButton->Enable();
|
||||
m_okButton->SetToolTip( wxEmptyString );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxString DIALOG_GIT_COMMIT::GetCommitMessage() const
|
||||
{
|
||||
return m_commitMessageTextCtrl->GetValue();
|
||||
}
|
||||
|
||||
|
||||
wxString DIALOG_GIT_COMMIT::GetAuthorName() const
|
||||
{
|
||||
wxString authorText = m_authorTextCtrl->GetValue();
|
||||
size_t pos = authorText.find( '<' );
|
||||
|
||||
if( pos != wxString::npos )
|
||||
return authorText.substr( 0, pos ).Trim();
|
||||
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
wxString DIALOG_GIT_COMMIT::GetAuthorEmail() const
|
||||
{
|
||||
wxString authorText = m_authorTextCtrl->GetValue();
|
||||
size_t startPos = authorText.find( '<' );
|
||||
size_t endPos = authorText.find( '>' );
|
||||
|
||||
if( startPos != wxString::npos && endPos != wxString::npos && startPos < endPos )
|
||||
return authorText.substr( startPos + 1, endPos - startPos - 1 ).Trim();
|
||||
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
std::vector<wxString> DIALOG_GIT_COMMIT::GetSelectedFiles() const
|
||||
{
|
||||
std::vector<wxString> selectedFiles;
|
||||
|
||||
long item = -1;
|
||||
while( ( item = m_listCtrl->GetNextItem( item, wxLIST_NEXT_ALL ) )
|
||||
!= -1 )
|
||||
{
|
||||
if( m_listCtrl->IsItemChecked( item ) )
|
||||
selectedFiles.push_back( m_listCtrl->GetItemText( item ) );
|
||||
}
|
||||
|
||||
return selectedFiles;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef DIALOG_GIT_COMMIT_H
|
||||
#define DIALOG_GIT_COMMIT_H
|
||||
|
||||
#include <dialog_shim.h>
|
||||
#include <git2.h>
|
||||
|
||||
class wxCheckBox;
|
||||
class wxListCtrl;
|
||||
class DIALOG_GIT_COMMIT : public DIALOG_SHIM
|
||||
{
|
||||
public:
|
||||
DIALOG_GIT_COMMIT( wxWindow* parent, git_repository* repo,
|
||||
const wxString& defaultAuthorName,
|
||||
const wxString& defaultAuthorEmail,
|
||||
const std::map<wxString, int>& filesToCommit );
|
||||
|
||||
wxString GetCommitMessage() const;
|
||||
|
||||
wxString GetAuthorName() const;
|
||||
|
||||
wxString GetAuthorEmail() const;
|
||||
|
||||
std::vector<wxString> GetSelectedFiles() const;
|
||||
|
||||
void OnTextChanged( wxCommandEvent& event );
|
||||
|
||||
private:
|
||||
wxTextCtrl* m_commitMessageTextCtrl;
|
||||
wxTextCtrl* m_authorTextCtrl;
|
||||
wxListCtrl* m_listCtrl;
|
||||
wxButton* m_okButton;
|
||||
|
||||
git_repository* m_repo;
|
||||
wxString m_defaultAuthorName;
|
||||
wxString m_defaultAuthorEmail;
|
||||
std::vector<wxString> m_filesToCommit;
|
||||
};
|
||||
|
||||
#endif // DIALOG_GIT_COMMIT_H
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/statusbr.h>
|
||||
|
||||
#include <dialog_shim.h>
|
||||
|
||||
class GIT_PROGRESS : public DIALOG_SHIM {
|
||||
public:
|
||||
GIT_PROGRESS(wxWindow* aParent, int aMaxValue1, int aMaxValue2);
|
||||
~GIT_PROGRESS();
|
||||
|
||||
void SetStatusText(const wxString& aText);
|
||||
bool UpdateProgressBar1(int aValue);
|
||||
bool UpdateProgressBar2(int aValue);
|
||||
|
||||
private:
|
||||
void OnCancel(wxCommandEvent& aEvent);
|
||||
|
||||
wxGauge* m_progBar1;
|
||||
wxGauge* m_progBar2;
|
||||
wxButton* m_cancelBtn;
|
||||
wxStatusBar* m_statusBar;
|
||||
bool m_cancelled;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "dialog_git_repository.h"
|
||||
#include <confirm.h>
|
||||
|
||||
#include <git2.h>
|
||||
#include <gestfich.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/regex.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
|
||||
DIALOG_GIT_REPOSITORY::DIALOG_GIT_REPOSITORY( wxWindow* aParent, git_repository* aRepository, wxString aURL ) :
|
||||
DIALOG_GIT_REPOSITORY_BASE( aParent ), m_repository( aRepository ), m_prevFile( wxEmptyString ),
|
||||
m_tested( 0 ), m_failedTest( false ), m_testError( wxEmptyString ), m_tempRepo( false ),
|
||||
m_repoType( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_LOCAL )
|
||||
{
|
||||
m_txtName->SetFocus();
|
||||
|
||||
if( !m_repository )
|
||||
{
|
||||
// Make a temporary repository to test the connection
|
||||
m_tempRepo = true;
|
||||
m_tempPath = wxFileName::CreateTempFileName( "kicadtestrepo" );
|
||||
|
||||
git_repository_init_options options = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
||||
options.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT;
|
||||
git_repository_init_ext( &m_repository, m_tempPath.ToStdString().c_str(), &options );
|
||||
}
|
||||
|
||||
if( !aURL.empty() )
|
||||
m_txtURL->SetValue( aURL );
|
||||
else
|
||||
extractClipboardData();
|
||||
|
||||
if( !m_txtURL->GetValue().IsEmpty() )
|
||||
updateURLData();
|
||||
|
||||
SetupStandardButtons();
|
||||
updateAuthControls();
|
||||
}
|
||||
|
||||
DIALOG_GIT_REPOSITORY::~DIALOG_GIT_REPOSITORY()
|
||||
{
|
||||
if( m_tempRepo )
|
||||
{
|
||||
git_repository_free( m_repository );
|
||||
RmDirRecursive( m_tempPath );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DIALOG_GIT_REPOSITORY::extractClipboardData()
|
||||
{
|
||||
if( wxTheClipboard->Open() && wxTheClipboard->IsSupported( wxDF_TEXT ) )
|
||||
{
|
||||
wxString clipboardText;
|
||||
wxTextDataObject textData;
|
||||
|
||||
if( wxTheClipboard->GetData( textData ) && !( clipboardText = textData.GetText() ).empty() )
|
||||
{
|
||||
if( std::get<0>( isValidHTTPS( clipboardText ) )
|
||||
|| std::get<0>( isValidSSH( clipboardText ) ) )
|
||||
m_txtURL->SetValue( clipboardText );
|
||||
}
|
||||
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::setDefaultSSHKey()
|
||||
{
|
||||
wxFileName sshKey;
|
||||
sshKey.SetPath( wxGetUserHome() );
|
||||
wxString retval;
|
||||
|
||||
sshKey.AppendDir( ".ssh" );
|
||||
sshKey.SetFullName( "id_rsa" );
|
||||
|
||||
if( sshKey.FileExists() )
|
||||
{
|
||||
retval = sshKey.GetFullPath();
|
||||
}
|
||||
else if( sshKey.SetFullName( "id_dsa" ); sshKey.FileExists() )
|
||||
{
|
||||
retval = sshKey.GetFullPath();
|
||||
}
|
||||
else if( sshKey.SetFullName( "id_ecdsa" ); sshKey.FileExists() )
|
||||
{
|
||||
retval = sshKey.GetFullPath();
|
||||
}
|
||||
|
||||
if( !retval.empty() )
|
||||
{
|
||||
m_fpSSHKey->SetFileName( retval );
|
||||
wxFileDirPickerEvent evt;
|
||||
evt.SetPath( retval );
|
||||
OnFileUpdated( evt );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::OnUpdateUI( wxUpdateUIEvent& event )
|
||||
{
|
||||
// event.Enable( !m_txtName->GetValue().IsEmpty() && !m_txtURL->GetValue().IsEmpty() );
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::SetEncrypted( bool aEncrypted )
|
||||
{
|
||||
if( aEncrypted )
|
||||
{
|
||||
m_txtPassword->Enable();
|
||||
m_txtPassword->SetToolTip( _( "Enter the password for the SSH key" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_txtPassword->SetValue( wxEmptyString );
|
||||
m_txtPassword->SetToolTip( wxEmptyString );
|
||||
m_txtPassword->Disable();
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<bool,wxString,wxString,wxString> DIALOG_GIT_REPOSITORY::isValidHTTPS( const wxString& url )
|
||||
{
|
||||
wxRegEx regex( R"((https?:\/\/)(([^:]+)(:([^@]+))?@)?([^\/]+\/[^\s]+))" );
|
||||
|
||||
if( regex.Matches( url ) )
|
||||
{
|
||||
wxString username = regex.GetMatch( url, 3 );
|
||||
wxString password = regex.GetMatch( url, 5 );
|
||||
wxString repoAddress = regex.GetMatch( url, 1 ) + regex.GetMatch( url, 6 );
|
||||
return std::make_tuple( true, username, password, repoAddress );
|
||||
}
|
||||
|
||||
return std::make_tuple( false, "", "", "" );
|
||||
}
|
||||
|
||||
|
||||
std::tuple<bool,wxString, wxString> DIALOG_GIT_REPOSITORY::isValidSSH( const wxString& url )
|
||||
{
|
||||
wxRegEx regex( R"((?:ssh:\/\/)?([^@]+)@([^\/]+\/[^\s]+))" );
|
||||
|
||||
if( regex.Matches( url ) )
|
||||
{
|
||||
wxString username = regex.GetMatch( url, 1 );
|
||||
wxString repoAddress = regex.GetMatch( url, 2 );
|
||||
return std::make_tuple( true, username, repoAddress );
|
||||
}
|
||||
|
||||
return std::make_tuple( false, "", "" );
|
||||
}
|
||||
|
||||
|
||||
static wxString get_repo_name( wxString& aRepoAddr )
|
||||
{
|
||||
wxString retval;
|
||||
size_t last_slash = aRepoAddr.find_last_of( '/' );
|
||||
bool ends_with_dot_git = aRepoAddr.EndsWith( ".git" );
|
||||
|
||||
if( ends_with_dot_git )
|
||||
retval = aRepoAddr.substr( last_slash + 1, aRepoAddr.size() - last_slash - 5 );
|
||||
else
|
||||
retval = aRepoAddr.substr( last_slash + 1, aRepoAddr.size() - last_slash );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::OnLocationExit( wxFocusEvent& event )
|
||||
{
|
||||
updateURLData();
|
||||
updateAuthControls();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::updateURLData()
|
||||
{
|
||||
wxString url = m_txtURL->GetValue();
|
||||
|
||||
if( url.IsEmpty() )
|
||||
return;
|
||||
|
||||
if( url.Contains( "https://" ) || url.Contains( "http://" ) )
|
||||
{
|
||||
auto [valid, username, password, repoAddress] = isValidHTTPS( url );
|
||||
|
||||
if( valid )
|
||||
{
|
||||
m_ConnType->SetSelection( static_cast<int>( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS ) );
|
||||
SetUsername( username );
|
||||
SetPassword( password );
|
||||
m_txtURL->SetValue( repoAddress );
|
||||
|
||||
if( m_txtName->GetValue().IsEmpty() )
|
||||
m_txtName->SetValue( get_repo_name( repoAddress ) );
|
||||
|
||||
}
|
||||
}
|
||||
else if( url.Contains( "ssh://" ) || url.Contains( "git@" ) )
|
||||
{
|
||||
auto [valid, username, repoAddress] = isValidSSH( url );
|
||||
|
||||
if( valid )
|
||||
{
|
||||
m_ConnType->SetSelection( static_cast<int>( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH ) );
|
||||
m_txtUsername->SetValue( username );
|
||||
m_txtURL->SetValue( repoAddress );
|
||||
|
||||
if( m_txtName->GetValue().IsEmpty() )
|
||||
m_txtName->SetValue( get_repo_name( repoAddress ) );
|
||||
|
||||
setDefaultSSHKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::OnTestClick( wxCommandEvent& event )
|
||||
{
|
||||
git_remote* remote = nullptr;
|
||||
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
|
||||
|
||||
// We track if we have already tried to connect.
|
||||
// If we have, the server may come back to offer another connection
|
||||
// type, so we need to keep track of how many times we have tried.
|
||||
m_tested = 0;
|
||||
|
||||
callbacks.credentials = []( git_cred** aOut, const char* aUrl, const char* aUsername,
|
||||
unsigned int aAllowedTypes, void* aPayload ) -> int
|
||||
{
|
||||
DIALOG_GIT_REPOSITORY* dialog = static_cast<DIALOG_GIT_REPOSITORY*>( aPayload );
|
||||
|
||||
if( dialog->GetRepoType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_LOCAL )
|
||||
return GIT_PASSTHROUGH;
|
||||
|
||||
if( aAllowedTypes & GIT_CREDENTIAL_USERNAME
|
||||
&& !( dialog->GetTested() & GIT_CREDTYPE_USERNAME ) )
|
||||
{
|
||||
wxString username = dialog->GetUsername().Trim().Trim( false );
|
||||
git_cred_username_new( aOut, username.ToStdString().c_str() );
|
||||
dialog->GetTested() |= GIT_CREDTYPE_USERNAME;
|
||||
}
|
||||
else if( dialog->GetRepoType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS
|
||||
&& ( aAllowedTypes & GIT_CREDENTIAL_USERPASS_PLAINTEXT )
|
||||
&& !( dialog->GetTested() & GIT_CREDTYPE_USERPASS_PLAINTEXT ) )
|
||||
{
|
||||
wxString username = dialog->GetUsername().Trim().Trim( false );
|
||||
wxString password = dialog->GetPassword().Trim().Trim( false );
|
||||
|
||||
git_cred_userpass_plaintext_new( aOut, username.ToStdString().c_str(),
|
||||
password.ToStdString().c_str() );
|
||||
dialog->GetTested() |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
|
||||
}
|
||||
else if( dialog->GetRepoType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH
|
||||
&& ( aAllowedTypes & GIT_CREDENTIAL_SSH_KEY )
|
||||
&& !( dialog->GetTested() & GIT_CREDTYPE_SSH_KEY ) )
|
||||
{
|
||||
// SSH key authentication
|
||||
wxString sshKey = dialog->GetRepoSSHPath();
|
||||
wxString sshPubKey = sshKey + ".pub";
|
||||
wxString username = dialog->GetUsername().Trim().Trim( false );
|
||||
wxString password = dialog->GetPassword().Trim().Trim( false );
|
||||
|
||||
git_cred_ssh_key_new( aOut, username.ToStdString().c_str(),
|
||||
sshPubKey.ToStdString().c_str(), sshKey.ToStdString().c_str(),
|
||||
password.ToStdString().c_str() );
|
||||
dialog->GetTested() |= GIT_CREDTYPE_SSH_KEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GIT_PASSTHROUGH;
|
||||
}
|
||||
|
||||
return GIT_OK;
|
||||
};
|
||||
|
||||
callbacks.payload = this;
|
||||
|
||||
git_remote_create_with_fetchspec( &remote, m_repository, "origin", m_txtURL->GetValue(),
|
||||
"+refs/heads/*:refs/remotes/origin/*" );
|
||||
|
||||
if( git_remote_connect( remote, GIT_DIRECTION_FETCH, &callbacks, nullptr, nullptr ) != GIT_OK )
|
||||
SetTestResult( true, git_error_last()->message );
|
||||
else
|
||||
SetTestResult( false, wxEmptyString );
|
||||
|
||||
git_remote_disconnect( remote );
|
||||
git_remote_free( remote );
|
||||
|
||||
auto dlg = wxMessageDialog( this, wxEmptyString, _( "Test connection" ), wxOK | wxICON_INFORMATION );
|
||||
|
||||
if( !m_failedTest )
|
||||
{
|
||||
dlg.SetMessage( _( "Connection successful" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
dlg.SetMessage( wxString::Format( _( "Could not connect to '%s' " ), m_txtURL->GetValue() ) );
|
||||
dlg.SetExtendedMessage( m_testError );
|
||||
}
|
||||
|
||||
dlg.ShowModal();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::OnFileUpdated( wxFileDirPickerEvent& aEvent )
|
||||
{
|
||||
wxString file = aEvent.GetPath();
|
||||
|
||||
if( file.ends_with( ".pub" ) )
|
||||
file = file.Left( file.size() - 4 );
|
||||
|
||||
std::ifstream ifs( file.ToStdString() );
|
||||
|
||||
if( !ifs.good() || !ifs.is_open() )
|
||||
{
|
||||
DisplayErrorMessage( this, wxString::Format( _( "Could not open private key '%s'" ), file ),
|
||||
wxString::Format( "%s: %d", std::strerror( errno ), errno ) );
|
||||
return;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::getline( ifs, line );
|
||||
|
||||
bool isValid = ( line.find( "PRIVATE KEY" ) != std::string::npos );
|
||||
bool isEncrypted = ( line.find( "ENCRYPTED" ) != std::string::npos );
|
||||
|
||||
if( !isValid )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Invalid SSH Key" ), _( "The selected file is not a valid SSH private key" ) );
|
||||
CallAfter( [this] { SetRepoSSHPath( m_prevFile ); } );
|
||||
return;
|
||||
}
|
||||
|
||||
if( isEncrypted )
|
||||
{
|
||||
m_txtPassword->Enable();
|
||||
m_txtPassword->SetToolTip( _( "Enter the password for the SSH key" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_txtPassword->SetValue( wxEmptyString );
|
||||
m_txtPassword->SetToolTip( wxEmptyString );
|
||||
m_txtPassword->Disable();
|
||||
}
|
||||
|
||||
ifs.close();
|
||||
|
||||
std::ifstream pubIfs( file + ".pub" );
|
||||
|
||||
if( !pubIfs.good() || !pubIfs.is_open() )
|
||||
{
|
||||
DisplayErrorMessage( this, wxString::Format( _( "Could not open public key '%s'" ), file + ".pub" ),
|
||||
wxString::Format( "%s: %d", std::strerror( errno ), errno ) );
|
||||
aEvent.SetPath( wxEmptyString );
|
||||
CallAfter( [this] { SetRepoSSHPath( m_prevFile ); } );
|
||||
return;
|
||||
}
|
||||
|
||||
m_prevFile = file;
|
||||
pubIfs.close();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::OnOKClick( wxCommandEvent& event )
|
||||
{
|
||||
// Save the repository details
|
||||
|
||||
if( m_txtName->GetValue().IsEmpty() )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Missing information" ), _( "Please enter a name for the repository" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_txtURL->GetValue().IsEmpty() )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Missing information" ), _( "Please enter a URL for the repository" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
EndModal( wxID_OK );
|
||||
}
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::updateAuthControls()
|
||||
{
|
||||
if( m_ConnType->GetSelection() == static_cast<int>( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_LOCAL ) )
|
||||
{
|
||||
m_panelAuth->Show( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_panelAuth->Show( true );
|
||||
|
||||
if( m_ConnType->GetSelection() == static_cast<int>( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH ) )
|
||||
{
|
||||
m_fpSSHKey->Show( true );
|
||||
m_labelSSH->Show( true );
|
||||
m_labelPass1->SetLabel( _( "SSH Key Password" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fpSSHKey->Show( false );
|
||||
m_labelSSH->Show( false );
|
||||
m_labelPass1->SetLabel( _( "Password" ) );
|
||||
setDefaultSSHKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_REPOSITORY::OnSelectConnType( wxCommandEvent& event )
|
||||
{
|
||||
updateAuthControls();
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef DIALOG_GIT_REPOSITORY_H_
|
||||
#define DIALOG_GIT_REPOSITORY_H_
|
||||
|
||||
#include "dialog_git_repository_base.h"
|
||||
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git2.h>
|
||||
|
||||
class DIALOG_GIT_REPOSITORY : public DIALOG_GIT_REPOSITORY_BASE
|
||||
{
|
||||
public:
|
||||
DIALOG_GIT_REPOSITORY( wxWindow* aParent, git_repository* aRepository, wxString aURL = wxEmptyString );
|
||||
~DIALOG_GIT_REPOSITORY() override;
|
||||
|
||||
void SetTestResult( bool aFailed, const wxString& aError )
|
||||
{
|
||||
m_failedTest = aFailed;
|
||||
m_testError = aError;
|
||||
}
|
||||
|
||||
void SetRepoType( KIGIT_COMMON::GIT_CONN_TYPE aType )
|
||||
{
|
||||
m_ConnType->SetSelection( static_cast<int>( aType ) );
|
||||
updateAuthControls();
|
||||
}
|
||||
|
||||
KIGIT_COMMON::GIT_CONN_TYPE GetRepoType() const { return static_cast<KIGIT_COMMON::GIT_CONN_TYPE>( m_ConnType->GetSelection() ); }
|
||||
|
||||
void SetRepoName( const wxString& aName ) { m_txtName->SetValue( aName ); }
|
||||
wxString GetRepoName() const { return m_txtName->GetValue(); }
|
||||
|
||||
void SetRepoURL( const wxString& aURL ) { m_txtURL->SetValue( aURL ); }
|
||||
wxString GetRepoURL() const { return m_txtURL->GetValue(); }
|
||||
|
||||
/**
|
||||
* @brief Get the Bare Repo U R L object
|
||||
*
|
||||
* @return wxString without the protocol
|
||||
*/
|
||||
wxString GetBareRepoURL() const
|
||||
{
|
||||
wxString url = m_txtURL->GetValue();
|
||||
|
||||
if( url.StartsWith( "https://" ) )
|
||||
url = url.Mid( 8 );
|
||||
else if( url.StartsWith( "http://" ) )
|
||||
url = url.Mid( 7 );
|
||||
else if( url.StartsWith( "ssh://" ) )
|
||||
url = url.Mid( 6 );
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
void SetUsername( const wxString& aUsername ) { m_txtUsername->SetValue( aUsername ); }
|
||||
wxString GetUsername() const { return m_txtUsername->GetValue(); }
|
||||
|
||||
void SetPassword( const wxString& aPassword ) { m_txtPassword->SetValue( aPassword ); }
|
||||
wxString GetPassword() const { return m_txtPassword->GetValue(); }
|
||||
|
||||
void SetRepoSSHPath( const wxString& aPath ) { m_fpSSHKey->SetFileName( aPath ); m_prevFile = aPath; }
|
||||
wxString GetRepoSSHPath() const { return m_fpSSHKey->GetFileName().GetFullPath(); }
|
||||
|
||||
unsigned& GetTested() { return m_tested; }
|
||||
|
||||
void SetEncrypted( bool aEncrypted = true );
|
||||
|
||||
private:
|
||||
void OnUpdateUI( wxUpdateUIEvent& event ) override;
|
||||
void OnLocationExit( wxFocusEvent& event ) override;
|
||||
void OnOKClick( wxCommandEvent& event ) override;
|
||||
|
||||
void OnSelectConnType( wxCommandEvent& event ) override;
|
||||
void OnTestClick( wxCommandEvent& event ) override;
|
||||
|
||||
void OnFileUpdated( wxFileDirPickerEvent& event ) override;
|
||||
|
||||
void setDefaultSSHKey();
|
||||
|
||||
void updateAuthControls();
|
||||
void updateURLData();
|
||||
bool extractClipboardData();
|
||||
|
||||
std::tuple<bool,wxString,wxString,wxString> isValidHTTPS( const wxString& url );
|
||||
std::tuple<bool,wxString, wxString> isValidSSH( const wxString& url );
|
||||
|
||||
git_repository* m_repository;
|
||||
|
||||
wxString m_prevFile;
|
||||
|
||||
unsigned m_tested;
|
||||
bool m_failedTest;
|
||||
wxString m_testError;
|
||||
|
||||
bool m_tempRepo;
|
||||
wxString m_tempPath;
|
||||
|
||||
KIGIT_COMMON::GIT_CONN_TYPE m_repoType;
|
||||
|
||||
};
|
||||
|
||||
#endif /* DIALOG_GIT_REPOSITORY_H_ */
|
|
@ -0,0 +1,172 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-254-gc2ef7767)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "dialog_git_repository_base.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DIALOG_GIT_REPOSITORY_BASE::DIALOG_GIT_REPOSITORY_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
|
||||
|
||||
wxBoxSizer* bSizerMain;
|
||||
bSizerMain = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_staticText1 = new wxStaticText( this, wxID_ANY, _("Connection"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText1->Wrap( -1 );
|
||||
bSizerMain->Add( m_staticText1, 0, wxLEFT|wxTOP, 10 );
|
||||
|
||||
m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
|
||||
bSizerMain->Add( m_staticline1, 0, wxEXPAND|wxTOP, 5 );
|
||||
|
||||
wxFlexGridSizer* fgSizer2;
|
||||
fgSizer2 = new wxFlexGridSizer( 0, 2, 0, 0 );
|
||||
fgSizer2->AddGrowableCol( 1 );
|
||||
fgSizer2->SetFlexibleDirection( wxBOTH );
|
||||
fgSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_staticText3 = new wxStaticText( this, wxID_ANY, _("Name"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText3->Wrap( -1 );
|
||||
fgSizer2->Add( m_staticText3, 0, wxALL, 5 );
|
||||
|
||||
m_txtName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizer2->Add( m_txtName, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_staticText4 = new wxStaticText( this, wxID_ANY, _("Location"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText4->Wrap( -1 );
|
||||
fgSizer2->Add( m_staticText4, 0, wxALL, 5 );
|
||||
|
||||
m_txtURL = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizer2->Add( m_txtURL, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_staticText9 = new wxStaticText( this, wxID_ANY, _("Connection Type"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText9->Wrap( -1 );
|
||||
fgSizer2->Add( m_staticText9, 0, wxALL, 5 );
|
||||
|
||||
wxBoxSizer* bSizer3;
|
||||
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxString m_ConnTypeChoices[] = { _("HTTPS"), _("SSH"), _("Local") };
|
||||
int m_ConnTypeNChoices = sizeof( m_ConnTypeChoices ) / sizeof( wxString );
|
||||
m_ConnType = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ConnTypeNChoices, m_ConnTypeChoices, 0 );
|
||||
m_ConnType->SetSelection( 0 );
|
||||
bSizer3->Add( m_ConnType, 1, wxEXPAND|wxLEFT|wxRIGHT, 5 );
|
||||
|
||||
|
||||
bSizer3->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizer2->Add( bSizer3, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
bSizerMain->Add( fgSizer2, 1, wxEXPAND, 5 );
|
||||
|
||||
m_panelAuth = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
wxBoxSizer* m_szAuth;
|
||||
m_szAuth = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
|
||||
m_szAuth->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
wxBoxSizer* bSizer11;
|
||||
bSizer11 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_staticText2 = new wxStaticText( m_panelAuth, wxID_ANY, _("Authentication"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText2->Wrap( -1 );
|
||||
bSizer11->Add( m_staticText2, 0, wxLEFT|wxTOP, 10 );
|
||||
|
||||
|
||||
bSizer11->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_szAuth->Add( bSizer11, 0, wxEXPAND, 5 );
|
||||
|
||||
m_staticline2 = new wxStaticLine( m_panelAuth, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
|
||||
m_szAuth->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 );
|
||||
|
||||
wxFlexGridSizer* fgSshSizer;
|
||||
fgSshSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
|
||||
fgSshSizer->AddGrowableCol( 1 );
|
||||
fgSshSizer->SetFlexibleDirection( wxBOTH );
|
||||
fgSshSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_labelSSH = new wxStaticText( m_panelAuth, wxID_ANY, _("SSH Private Key"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_labelSSH->Wrap( -1 );
|
||||
fgSshSizer->Add( m_labelSSH, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxRESERVE_SPACE_EVEN_IF_HIDDEN, 5 );
|
||||
|
||||
wxBoxSizer* bSizer41;
|
||||
bSizer41 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_fpSSHKey = new wxFilePickerCtrl( m_panelAuth, wxID_ANY, wxEmptyString, _("Select SSH private key file"), _("*"), wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE|wxFLP_FILE_MUST_EXIST|wxFLP_OPEN );
|
||||
bSizer41->Add( m_fpSSHKey, 1, wxEXPAND|wxLEFT|wxRESERVE_SPACE_EVEN_IF_HIDDEN|wxRIGHT, 5 );
|
||||
|
||||
m_btnTest = new wxButton( m_panelAuth, wxID_ANY, _("Test"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizer41->Add( m_btnTest, 0, wxLEFT|wxRIGHT, 5 );
|
||||
|
||||
|
||||
fgSshSizer->Add( bSizer41, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticText11 = new wxStaticText( m_panelAuth, wxID_ANY, _("Username"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText11->Wrap( -1 );
|
||||
fgSshSizer->Add( m_staticText11, 0, wxALL, 5 );
|
||||
|
||||
m_txtUsername = new wxTextCtrl( m_panelAuth, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSshSizer->Add( m_txtUsername, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_labelPass1 = new wxStaticText( m_panelAuth, wxID_ANY, _("SSH Key Password"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_labelPass1->Wrap( -1 );
|
||||
fgSshSizer->Add( m_labelPass1, 0, wxALL, 5 );
|
||||
|
||||
m_txtPassword = new wxTextCtrl( m_panelAuth, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSshSizer->Add( m_txtPassword, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_szAuth->Add( fgSshSizer, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
m_panelAuth->SetSizer( m_szAuth );
|
||||
m_panelAuth->Layout();
|
||||
m_szAuth->Fit( m_panelAuth );
|
||||
bSizerMain->Add( m_panelAuth, 1, wxALL|wxEXPAND|wxRESERVE_SPACE_EVEN_IF_HIDDEN, 0 );
|
||||
|
||||
m_sdbSizer = new wxStdDialogButtonSizer();
|
||||
m_sdbSizerOK = new wxButton( this, wxID_OK );
|
||||
m_sdbSizer->AddButton( m_sdbSizerOK );
|
||||
m_sdbSizerCancel = new wxButton( this, wxID_CANCEL );
|
||||
m_sdbSizer->AddButton( m_sdbSizerCancel );
|
||||
m_sdbSizer->Realize();
|
||||
|
||||
bSizerMain->Add( m_sdbSizer, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bSizerMain );
|
||||
this->Layout();
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
|
||||
// Connect Events
|
||||
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnClose ) );
|
||||
this->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnUpdateUI ) );
|
||||
m_txtURL->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnLocationExit ), NULL, this );
|
||||
m_ConnType->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnSelectConnType ), NULL, this );
|
||||
m_fpSSHKey->Connect( wxEVT_COMMAND_FILEPICKER_CHANGED, wxFileDirPickerEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnFileUpdated ), NULL, this );
|
||||
m_btnTest->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnTestClick ), NULL, this );
|
||||
m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnOKClick ), NULL, this );
|
||||
}
|
||||
|
||||
DIALOG_GIT_REPOSITORY_BASE::~DIALOG_GIT_REPOSITORY_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnClose ) );
|
||||
this->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnUpdateUI ) );
|
||||
m_txtURL->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnLocationExit ), NULL, this );
|
||||
m_ConnType->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnSelectConnType ), NULL, this );
|
||||
m_fpSSHKey->Disconnect( wxEVT_COMMAND_FILEPICKER_CHANGED, wxFileDirPickerEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnFileUpdated ), NULL, this );
|
||||
m_btnTest->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnTestClick ), NULL, this );
|
||||
m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GIT_REPOSITORY_BASE::OnOKClick ), NULL, this );
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,82 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-254-gc2ef7767)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
#include "dialog_shim.h"
|
||||
#include <wx/string.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/filepicker.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/dialog.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class DIALOG_GIT_REPOSITORY_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class DIALOG_GIT_REPOSITORY_BASE : public DIALOG_SHIM
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_staticText1;
|
||||
wxStaticLine* m_staticline1;
|
||||
wxStaticText* m_staticText3;
|
||||
wxTextCtrl* m_txtName;
|
||||
wxStaticText* m_staticText4;
|
||||
wxTextCtrl* m_txtURL;
|
||||
wxStaticText* m_staticText9;
|
||||
wxChoice* m_ConnType;
|
||||
wxPanel* m_panelAuth;
|
||||
wxStaticText* m_staticText2;
|
||||
wxStaticLine* m_staticline2;
|
||||
wxStaticText* m_labelSSH;
|
||||
wxFilePickerCtrl* m_fpSSHKey;
|
||||
wxButton* m_btnTest;
|
||||
wxStaticText* m_staticText11;
|
||||
wxTextCtrl* m_txtUsername;
|
||||
wxStaticText* m_labelPass1;
|
||||
wxTextCtrl* m_txtPassword;
|
||||
wxStdDialogButtonSizer* m_sdbSizer;
|
||||
wxButton* m_sdbSizerOK;
|
||||
wxButton* m_sdbSizerCancel;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
|
||||
virtual void OnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); }
|
||||
virtual void OnLocationExit( wxFocusEvent& event ) { event.Skip(); }
|
||||
virtual void OnSelectConnType( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnFileUpdated( wxFileDirPickerEvent& event ) { event.Skip(); }
|
||||
virtual void OnTestClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnOKClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
DIALOG_GIT_REPOSITORY_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Git Repository"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 682,598 ), long style = wxCAPTION|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
|
||||
|
||||
~DIALOG_GIT_REPOSITORY_BASE();
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include "dialog_git_switch.h"
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include <git2.h>
|
||||
|
||||
|
||||
DIALOG_GIT_SWITCH::DIALOG_GIT_SWITCH( wxWindow* aParent, git_repository* aRepository ) :
|
||||
DIALOG_SHIM( aParent, wxID_ANY, _( "Git Branch Switch" ), wxDefaultPosition, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
|
||||
m_timer( this ), m_repository( aRepository )
|
||||
{
|
||||
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
// Add explanation text
|
||||
wxStaticText* explanationText =
|
||||
new wxStaticText( this, wxID_ANY, _( "Select or enter a branch name:" ) );
|
||||
sizer->Add( explanationText, 0, wxALL, 10 );
|
||||
|
||||
// Add branch list with three columns
|
||||
m_branchList = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxLC_REPORT | wxLC_SINGLE_SEL );
|
||||
m_branchList->InsertColumn( 0, _( "Branch" ) );
|
||||
m_branchList->InsertColumn( 1, _( "Last Commit" ) );
|
||||
m_branchList->InsertColumn( 2, _( "Last Updated" ) );
|
||||
sizer->Add( m_branchList, 1, wxALL | wxEXPAND, 10 );
|
||||
|
||||
// Add branch name text box
|
||||
m_branchNameText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_PROCESS_ENTER );
|
||||
sizer->Add( m_branchNameText, 0, wxALL | wxEXPAND, 10 );
|
||||
|
||||
// Add buttons
|
||||
wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
|
||||
m_switchButton = new wxButton( this, wxID_OK, _( "Switch" ) );
|
||||
buttonSizer->AddButton( m_switchButton );
|
||||
m_switchButton->Disable();
|
||||
wxButton* cancelButton = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
|
||||
buttonSizer->AddButton( cancelButton );
|
||||
buttonSizer->Realize();
|
||||
sizer->Add( buttonSizer, 0, wxALIGN_RIGHT | wxALL, 10 );
|
||||
|
||||
// Bind events
|
||||
Bind( wxEVT_LIST_ITEM_SELECTED, &DIALOG_GIT_SWITCH::OnBranchListSelection, this, m_branchList->GetId() );
|
||||
Bind( wxEVT_LIST_ITEM_ACTIVATED, &DIALOG_GIT_SWITCH::OnBranchListDClick, this, m_branchList->GetId() );
|
||||
Bind( wxEVT_BUTTON, &DIALOG_GIT_SWITCH::OnSwitchButton, this, m_switchButton->GetId() );
|
||||
Bind( wxEVT_BUTTON, &DIALOG_GIT_SWITCH::OnCancelButton, this, cancelButton->GetId() );
|
||||
Bind( wxEVT_TEXT, &DIALOG_GIT_SWITCH::OnTextChanged, this, m_branchNameText->GetId() );
|
||||
Bind( wxEVT_TIMER, &DIALOG_GIT_SWITCH::OnTimer, this, m_timer.GetId() );
|
||||
|
||||
// Populate branch list
|
||||
PopulateBranchList();
|
||||
|
||||
// Set sizer for the dialog
|
||||
SetSizerAndFit( sizer );
|
||||
|
||||
finishDialogSettings();
|
||||
|
||||
m_existingBranch = false;
|
||||
}
|
||||
|
||||
DIALOG_GIT_SWITCH::~DIALOG_GIT_SWITCH()
|
||||
{
|
||||
StopTimer();
|
||||
Unbind( wxEVT_TIMER, &DIALOG_GIT_SWITCH::OnTimer, this, m_timer.GetId() );
|
||||
}
|
||||
|
||||
void DIALOG_GIT_SWITCH::PopulateBranchList()
|
||||
{
|
||||
m_branchList->DeleteAllItems();
|
||||
|
||||
// Get the branches
|
||||
GetBranches();
|
||||
|
||||
// Populate the list
|
||||
for( auto& [ name, data ] : m_branches )
|
||||
{
|
||||
wxDateTime lastUpdated( data.lastUpdated );
|
||||
wxString lastUpdatedString = lastUpdated.Format();
|
||||
|
||||
long itemIndex = m_branchList->InsertItem( m_branchList->GetItemCount(), name );
|
||||
m_branchList->SetItem( itemIndex, 1, data.commitString );
|
||||
m_branchList->SetItem( itemIndex, 2, lastUpdatedString );
|
||||
}
|
||||
|
||||
m_branchList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
|
||||
m_branchList->SetColumnWidth( 1, wxLIST_AUTOSIZE );
|
||||
m_branchList->SetColumnWidth( 2, wxLIST_AUTOSIZE );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::OnBranchListDClick( wxListEvent& aEvent )
|
||||
{
|
||||
int selection = aEvent.GetIndex();
|
||||
|
||||
if( selection != wxNOT_FOUND )
|
||||
{
|
||||
wxString branchName = m_branchList->GetItemText( selection );
|
||||
m_branchNameText->SetValue( branchName );
|
||||
|
||||
if( branchName != m_currentBranch )
|
||||
EndModal( wxID_OK );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::OnBranchListSelection( wxListEvent& aEvent )
|
||||
{
|
||||
int selection = aEvent.GetIndex();
|
||||
|
||||
if( selection != wxNOT_FOUND )
|
||||
{
|
||||
wxString branchName = m_branchList->GetItemText( selection );
|
||||
m_branchNameText->SetValue( branchName );
|
||||
m_switchButton->SetLabel( _( "Switch" ) );
|
||||
m_switchButton->Enable( branchName != m_currentBranch );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Deselect all elements in the list
|
||||
for( int ii = 0; ii < m_branchList->GetItemCount(); ++ii )
|
||||
m_branchList->SetItemState( ii, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void DIALOG_GIT_SWITCH::OnSwitchButton(wxCommandEvent& aEvent)
|
||||
{
|
||||
wxString branchName = m_branchNameText->GetValue();
|
||||
|
||||
// Check if the branch name exists
|
||||
bool branchExists = m_branches.count(branchName);
|
||||
|
||||
if (branchExists)
|
||||
{
|
||||
EndModal(wxID_OK); // Return Switch code
|
||||
}
|
||||
else
|
||||
{
|
||||
EndModal(wxID_ADD); // Return Add code
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::OnCancelButton(wxCommandEvent& aEvent)
|
||||
{
|
||||
EndModal(wxID_CANCEL); // Return Cancel code
|
||||
}
|
||||
|
||||
|
||||
wxString DIALOG_GIT_SWITCH::GetBranchName() const
|
||||
{
|
||||
return m_branchNameText->GetValue();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::StartTimer()
|
||||
{
|
||||
m_timer.Start( 500, true );
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::StopTimer()
|
||||
{
|
||||
m_timer.Stop();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::OnTimer( wxTimerEvent& aEvt )
|
||||
{
|
||||
wxString branchName = m_branchNameText->GetValue();
|
||||
|
||||
if( branchName == m_lastEnteredText )
|
||||
return;
|
||||
|
||||
m_lastEnteredText = branchName;
|
||||
|
||||
// Check if the branch name exists
|
||||
bool branchExists = m_branches.count( branchName );
|
||||
|
||||
if( branchExists )
|
||||
{
|
||||
m_switchButton->SetLabel( _( "Switch" ) );
|
||||
m_switchButton->Enable( branchName != m_currentBranch );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_switchButton->SetLabel( _( "Add" ) );
|
||||
m_switchButton->Enable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::OnTextChanged( wxCommandEvent& aEvt )
|
||||
{
|
||||
StartTimer();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_GIT_SWITCH::GetBranches()
|
||||
{
|
||||
// Clear the branch list
|
||||
m_branches.clear();
|
||||
|
||||
git_branch_iterator* branchIterator = nullptr;
|
||||
git_branch_t branchType;
|
||||
|
||||
// Get Current Branch
|
||||
git_reference* currentBranchReference = nullptr;
|
||||
git_repository_head( ¤tBranchReference, m_repository );
|
||||
|
||||
// Get the current branch name
|
||||
if( currentBranchReference )
|
||||
{
|
||||
m_currentBranch = git_reference_shorthand( currentBranchReference );
|
||||
git_reference_free( currentBranchReference );
|
||||
}
|
||||
|
||||
// Initialize branch iterator
|
||||
git_branch_iterator_new( &branchIterator, m_repository, GIT_BRANCH_ALL );
|
||||
|
||||
// Iterate over local branches
|
||||
git_reference* branchReference = nullptr;
|
||||
while( git_branch_next( &branchReference, &branchType, branchIterator ) == 0 )
|
||||
{
|
||||
// Get the branch OID
|
||||
const git_oid* branchOid = git_reference_target( branchReference );
|
||||
|
||||
// Skip this branch if it doesn't have an OID
|
||||
if( !branchOid )
|
||||
{
|
||||
git_reference_free( branchReference );
|
||||
continue;
|
||||
}
|
||||
|
||||
git_commit* commit = nullptr;
|
||||
|
||||
if( git_commit_lookup( &commit, m_repository, branchOid ) )
|
||||
{
|
||||
// Skip this branch if it doesn't have a commit
|
||||
git_reference_free( branchReference );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retrieve commit details
|
||||
BranchData branchData;
|
||||
branchData.commitString = git_commit_message( commit );
|
||||
branchData.lastUpdated = static_cast<time_t>( git_commit_time( commit ) );
|
||||
branchData.isRemote = branchType == GIT_BRANCH_REMOTE;
|
||||
|
||||
m_branches[git_reference_shorthand( branchReference )] = branchData;
|
||||
|
||||
git_commit_free( commit );
|
||||
git_reference_free( branchReference );
|
||||
}
|
||||
|
||||
git_branch_iterator_free( branchIterator );
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DIALOG_GIT_SWITCH_H
|
||||
#define DIALOG_GIT_SWITCH_H
|
||||
|
||||
#include <dialog_shim.h>
|
||||
#include <git2.h>
|
||||
|
||||
class wxButton;
|
||||
class wxListView;
|
||||
class wxTextCtrl;
|
||||
class wxTimer;
|
||||
class wxListEvent;
|
||||
|
||||
struct BranchData
|
||||
{
|
||||
wxString commitString;
|
||||
time_t lastUpdated;
|
||||
bool isRemote;
|
||||
};
|
||||
|
||||
class DIALOG_GIT_SWITCH : public DIALOG_SHIM
|
||||
{
|
||||
public:
|
||||
DIALOG_GIT_SWITCH(wxWindow* aParent, git_repository* aRepository);
|
||||
virtual ~DIALOG_GIT_SWITCH();
|
||||
|
||||
wxString GetBranchName() const;
|
||||
|
||||
private:
|
||||
void PopulateBranchList();
|
||||
void OnBranchListSelection(wxListEvent& event);
|
||||
void OnBranchListDClick(wxListEvent& event);
|
||||
void OnSwitchButton(wxCommandEvent& event);
|
||||
void OnCancelButton(wxCommandEvent& event);
|
||||
void OnTextChanged(wxCommandEvent& event);
|
||||
void OnTimer(wxTimerEvent& event);
|
||||
void GetBranches();
|
||||
|
||||
wxListView* m_branchList;
|
||||
wxTextCtrl* m_branchNameText;
|
||||
wxButton* m_switchButton;
|
||||
wxTimer m_timer;
|
||||
|
||||
wxString m_currentBranch;
|
||||
|
||||
git_repository* m_repository;
|
||||
wxString m_lastEnteredText;
|
||||
bool m_existingBranch;
|
||||
|
||||
std::map<wxString, BranchData> m_branches;
|
||||
|
||||
void StartTimer();
|
||||
void StopTimer();
|
||||
};
|
||||
|
||||
#endif // DIALOG_GIT_SWITCH_H
|
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "panel_git_repos.h"
|
||||
|
||||
#include <bitmaps.h>
|
||||
#include <dialogs/git/dialog_git_repository.h>
|
||||
#include <kiplatform/secrets.h>
|
||||
#include <pgm_base.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <widgets/std_bitmap_button.h>
|
||||
#include <widgets/wx_grid.h>
|
||||
|
||||
#include <git2.h>
|
||||
#include <wx/bmpbuttn.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
|
||||
PANEL_GIT_REPOS::PANEL_GIT_REPOS( wxWindow* aParent ) : PANEL_GIT_REPOS_BASE( aParent)
|
||||
{
|
||||
|
||||
m_btnAddRepo->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
|
||||
m_btnEditRepo->SetBitmap( KiBitmap( BITMAPS::small_edit ) );
|
||||
m_btnDelete->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
|
||||
|
||||
}
|
||||
|
||||
PANEL_GIT_REPOS::~PANEL_GIT_REPOS()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PANEL_GIT_REPOS::ResetPanel()
|
||||
{
|
||||
m_grid->ClearGrid();
|
||||
m_cbDefault->SetValue( true );
|
||||
m_author->SetValue( wxEmptyString );
|
||||
m_authorEmail->SetValue( wxEmptyString );
|
||||
}
|
||||
|
||||
static std::pair<wxString, wxString> getDefaultAuthorEmail()
|
||||
{
|
||||
wxString name;
|
||||
wxString email;
|
||||
git_config_entry* name_c = nullptr;
|
||||
git_config_entry* email_c = nullptr;
|
||||
|
||||
git_config* config = nullptr;
|
||||
|
||||
if( git_config_open_default( &config ) != 0 )
|
||||
{
|
||||
printf( "Failed to open default Git config: %s\n", giterr_last()->message );
|
||||
return std::make_pair( name, email );
|
||||
}
|
||||
|
||||
if( git_config_get_entry( &name_c, config, "user.name" ) != 0 )
|
||||
{
|
||||
printf( "Failed to get user.name from Git config: %s\n", giterr_last()->message );
|
||||
}
|
||||
if( git_config_get_entry( &email_c, config, "user.email" ) != 0 )
|
||||
{
|
||||
printf( "Failed to get user.email from Git config: %s\n", giterr_last()->message );
|
||||
}
|
||||
|
||||
if( name_c )
|
||||
name = name_c->value;
|
||||
|
||||
if( email_c )
|
||||
email = email_c->value;
|
||||
|
||||
git_config_entry_free( name_c );
|
||||
git_config_entry_free( email_c );
|
||||
git_config_free( config );
|
||||
|
||||
return std::make_pair( name, email );
|
||||
}
|
||||
|
||||
bool PANEL_GIT_REPOS::TransferDataFromWindow()
|
||||
{
|
||||
COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
|
||||
auto& repos = settings->m_Git.repositories;
|
||||
|
||||
repos.clear();
|
||||
|
||||
for( int row = 0; row < m_grid->GetNumberRows(); row++ )
|
||||
{
|
||||
COMMON_SETTINGS::GIT_REPOSITORY repo;
|
||||
|
||||
repo.active = m_grid->GetCellValue( row, COL_ACTIVE ) == "1";
|
||||
repo.name = m_grid->GetCellValue( row, COL_NAME );
|
||||
repo.path = m_grid->GetCellValue( row, COL_PATH );
|
||||
repo.authType = m_grid->GetCellValue( row, COL_AUTH_TYPE );
|
||||
repo.username = m_grid->GetCellValue( row, COL_USERNAME );
|
||||
|
||||
KIPLATFORM::SECRETS::StoreSecret( repo.path, repo.username, m_grid->GetCellValue( row, COL_PASSWORD ) );
|
||||
repo.ssh_path = m_grid->GetCellValue( row, COL_SSH_PATH );
|
||||
repos.push_back( repo );
|
||||
}
|
||||
|
||||
settings->m_Git.useDefaultAuthor = m_cbDefault->GetValue();
|
||||
settings->m_Git.authorName = m_author->GetValue();
|
||||
settings->m_Git.authorEmail = m_authorEmail->GetValue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool testRepositoryConnection( COMMON_SETTINGS::GIT_REPOSITORY& repository)
|
||||
{
|
||||
git_libgit2_init();
|
||||
|
||||
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_SETTINGS::GIT_REPOSITORY* repo;
|
||||
bool success;
|
||||
} callbacksPayload;
|
||||
|
||||
callbacksPayload cb_data( { &repository, true } ); // If we don't need authentication, then, we are successful
|
||||
callbacks.payload = &cb_data;
|
||||
callbacks.credentials = [](git_cred** out, const char* url, const char* username, unsigned int allowed_types, void* payload) -> int {
|
||||
|
||||
// If we are asking for credentials, then, we need authentication
|
||||
|
||||
callbacksPayload* data = static_cast<callbacksPayload*>(payload);
|
||||
|
||||
data->success = false;
|
||||
|
||||
if( allowed_types & GIT_CREDTYPE_USERNAME )
|
||||
{
|
||||
data->success = true;
|
||||
}
|
||||
else if( data->repo->authType == "ssh" && ( allowed_types & GIT_CREDTYPE_SSH_KEY ) )
|
||||
{
|
||||
wxString sshKeyPath = data->repo->ssh_path;
|
||||
|
||||
// Check if the SSH key exists and is readable
|
||||
if( wxFileExists( sshKeyPath ) && wxFile::Access( sshKeyPath, wxFile::read ) )
|
||||
data->success = true;
|
||||
}
|
||||
else if( data->repo->authType == "password" )
|
||||
{
|
||||
data->success = ( allowed_types & GIT_CREDTYPE_USERPASS_PLAINTEXT );
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Create a temporary directory to initialize the Git repository
|
||||
wxString tempDirPath = wxFileName::CreateTempFileName(wxT("kigit_temp"));
|
||||
wxMkDir(tempDirPath, wxS_DIR_DEFAULT );
|
||||
|
||||
// Initialize the Git repository
|
||||
git_repository* repo = nullptr;
|
||||
int result = git_repository_init(&repo, tempDirPath.mb_str(wxConvUTF8), 0);
|
||||
if (result != 0) {
|
||||
git_repository_free(repo);
|
||||
git_libgit2_shutdown();
|
||||
wxRmdir(tempDirPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
git_remote* remote = nullptr;
|
||||
result = git_remote_create_anonymous(&remote, repo, tempDirPath.mb_str(wxConvUTF8));
|
||||
if (result != 0) {
|
||||
git_remote_free(remote);
|
||||
git_repository_free(repo);
|
||||
git_libgit2_shutdown();
|
||||
wxRmdir(tempDirPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't really care about the result of this call, the authentication callback
|
||||
// will set the return values we need
|
||||
git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, nullptr, nullptr);
|
||||
|
||||
git_remote_disconnect(remote);
|
||||
git_remote_free(remote);
|
||||
git_repository_free(repo);
|
||||
|
||||
git_libgit2_shutdown();
|
||||
|
||||
// Clean up the temporary directory
|
||||
wxRmdir(tempDirPath);
|
||||
|
||||
return cb_data.success;
|
||||
}
|
||||
|
||||
bool PANEL_GIT_REPOS::TransferDataToWindow()
|
||||
{
|
||||
COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
|
||||
|
||||
m_grid->ClearGrid();
|
||||
|
||||
for( COMMON_SETTINGS::GIT_REPOSITORY& repo : settings->m_Git.repositories )
|
||||
{
|
||||
if( repo.name.IsEmpty() || repo.path.IsEmpty() )
|
||||
continue;
|
||||
|
||||
int row = m_grid->GetNumberRows();
|
||||
m_grid->AppendRows( 1 );
|
||||
|
||||
m_grid->SetCellRenderer( row, COL_ACTIVE, new wxGridCellBoolRenderer() );
|
||||
m_grid->SetCellEditor( row, COL_ACTIVE, new wxGridCellBoolEditor() );
|
||||
m_grid->SetCellValue( row, COL_ACTIVE, repo.active ? "1" : "0" );
|
||||
|
||||
m_grid->SetCellValue( row, COL_NAME, repo.name );
|
||||
m_grid->SetCellValue( row, COL_PATH, repo.path );
|
||||
m_grid->SetCellValue( row, COL_AUTH_TYPE, repo.authType );
|
||||
m_grid->SetCellValue( row, COL_USERNAME, repo.username );
|
||||
|
||||
wxString password;
|
||||
KIPLATFORM::SECRETS::GetSecret( repo.path, repo.username, password );
|
||||
m_grid->SetCellValue( row, COL_PASSWORD, password );
|
||||
m_grid->SetCellValue( row, COL_SSH_PATH, repo.ssh_path );
|
||||
|
||||
if( repo.active )
|
||||
m_grid->SetCellValue( row, 3, testRepositoryConnection( repo ) ? "C" : "NC" );
|
||||
|
||||
}
|
||||
|
||||
m_cbDefault->SetValue( settings->m_Git.useDefaultAuthor );
|
||||
|
||||
if( settings->m_Git.useDefaultAuthor )
|
||||
{
|
||||
auto defaultAuthor = getDefaultAuthorEmail();
|
||||
m_author->SetValue( defaultAuthor.first );
|
||||
m_authorEmail->SetValue( defaultAuthor.second );
|
||||
m_author->Disable();
|
||||
m_authorEmail->Disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_author->SetValue( settings->m_Git.authorName );
|
||||
m_authorEmail->SetValue( settings->m_Git.authorEmail );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PANEL_GIT_REPOS::onDefaultClick( wxCommandEvent& event )
|
||||
{
|
||||
m_author->Enable( !m_cbDefault->GetValue() );
|
||||
m_authorEmail->Enable( !m_cbDefault->GetValue() );
|
||||
m_authorLabel->Enable( !m_cbDefault->GetValue() );
|
||||
m_authorEmailLabel->Enable( !m_cbDefault->GetValue() );
|
||||
}
|
||||
|
||||
|
||||
void PANEL_GIT_REPOS::onGridDClick( wxGridEvent& event )
|
||||
{
|
||||
if( m_grid->GetNumberRows() <= 0 )
|
||||
{
|
||||
wxCommandEvent evt;
|
||||
onAddClick( evt );
|
||||
return;
|
||||
}
|
||||
|
||||
int row = event.GetRow();
|
||||
|
||||
if( row < 0 || row >= m_grid->GetNumberRows() )
|
||||
return;
|
||||
|
||||
DIALOG_GIT_REPOSITORY dialog( this, nullptr );
|
||||
|
||||
dialog.SetRepoName( m_grid->GetCellValue( row, COL_NAME ) );
|
||||
dialog.SetRepoURL( m_grid->GetCellValue( row, COL_PATH ) );
|
||||
dialog.SetUsername( m_grid->GetCellValue( row, COL_USERNAME ) );
|
||||
dialog.SetRepoSSHPath( m_grid->GetCellValue( row, COL_SSH_PATH ) );
|
||||
dialog.SetPassword( m_grid->GetCellValue( row, COL_PASSWORD ) );
|
||||
|
||||
wxString type = m_grid->GetCellValue( row, COL_AUTH_TYPE );
|
||||
|
||||
if( type == "password" )
|
||||
dialog.SetRepoType( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS );
|
||||
else if( type == "ssh" )
|
||||
dialog.SetRepoType( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH );
|
||||
else
|
||||
dialog.SetRepoType( KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_LOCAL);
|
||||
|
||||
if( dialog.ShowModal() == wxID_OK )
|
||||
{
|
||||
m_grid->SetCellValue( row, COL_NAME, dialog.GetRepoName() );
|
||||
m_grid->SetCellValue( row, COL_PATH, dialog.GetRepoURL() );
|
||||
m_grid->SetCellValue( row, COL_USERNAME, dialog.GetUsername() );
|
||||
m_grid->SetCellValue( row, COL_SSH_PATH, dialog.GetRepoSSHPath() );
|
||||
m_grid->SetCellValue( row, COL_PASSWORD, dialog.GetPassword() );
|
||||
|
||||
if( dialog.GetRepoType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS )
|
||||
{
|
||||
m_grid->SetCellValue( row, COL_AUTH_TYPE, "password" );
|
||||
}
|
||||
else if( dialog.GetRepoType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH )
|
||||
{
|
||||
m_grid->SetCellValue( row, COL_AUTH_TYPE, "ssh" );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_grid->SetCellValue( row, COL_AUTH_TYPE, "none" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PANEL_GIT_REPOS::onAddClick( wxCommandEvent& event )
|
||||
{
|
||||
|
||||
DIALOG_GIT_REPOSITORY dialog( m_parent, nullptr );
|
||||
|
||||
if( dialog.ShowModal() == wxID_OK )
|
||||
{
|
||||
int row = m_grid->GetNumberRows();
|
||||
m_grid->AppendRows( 1 );
|
||||
|
||||
m_grid->SetCellValue( row, COL_NAME, dialog.GetRepoName() );
|
||||
m_grid->SetCellValue( row, COL_PATH, dialog.GetRepoURL() );
|
||||
m_grid->SetCellValue( row, COL_USERNAME, dialog.GetUsername() );
|
||||
m_grid->SetCellValue( row, COL_SSH_PATH, dialog.GetRepoSSHPath() );
|
||||
m_grid->SetCellValue( row, COL_PASSWORD, dialog.GetPassword() );
|
||||
|
||||
if( dialog.GetRepoType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS )
|
||||
{
|
||||
m_grid->SetCellValue( row, COL_AUTH_TYPE, "password" );
|
||||
}
|
||||
else if( dialog.GetRepoType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH )
|
||||
{
|
||||
m_grid->SetCellValue( row, COL_AUTH_TYPE, "ssh" );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_grid->SetCellValue( row, COL_AUTH_TYPE, "none" );
|
||||
}
|
||||
|
||||
m_grid->MakeCellVisible( row, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PANEL_GIT_REPOS::onEditClick( wxCommandEvent& event )
|
||||
{
|
||||
wxGridEvent evt( m_grid->GetId(), wxEVT_GRID_CELL_LEFT_DCLICK, m_grid,
|
||||
m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
|
||||
onGridDClick( evt );
|
||||
}
|
||||
|
||||
|
||||
void PANEL_GIT_REPOS::onDeleteClick( wxCommandEvent& event )
|
||||
{
|
||||
if( !m_grid->CommitPendingChanges() || m_grid->GetNumberRows() <= 0 )
|
||||
return;
|
||||
|
||||
int curRow = m_grid->GetGridCursorRow();
|
||||
|
||||
m_grid->DeleteRows( curRow );
|
||||
|
||||
curRow = std::max( 0, curRow - 1 );
|
||||
m_grid->MakeCellVisible( curRow, m_grid->GetGridCursorCol() );
|
||||
m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() );
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PANEL_GIT_REPOS_H
|
||||
#define PANEL_GIT_REPOS_H
|
||||
|
||||
#include <git/panel_git_repos_base.h>
|
||||
#include <widgets/wx_grid.h>
|
||||
|
||||
class PANEL_GIT_REPOS : public PANEL_GIT_REPOS_BASE
|
||||
{
|
||||
public:
|
||||
PANEL_GIT_REPOS( wxWindow* parent );
|
||||
~PANEL_GIT_REPOS() override;
|
||||
|
||||
void ResetPanel() override;
|
||||
|
||||
bool TransferDataFromWindow() override;
|
||||
bool TransferDataToWindow() override;
|
||||
|
||||
enum COLS
|
||||
{
|
||||
COL_ACTIVE = 0,
|
||||
COL_NAME,
|
||||
COL_PATH,
|
||||
COL_STATUS,
|
||||
COL_AUTH_TYPE,
|
||||
COL_USERNAME,
|
||||
COL_PASSWORD,
|
||||
COL_SSH_KEY,
|
||||
COL_SSH_PATH
|
||||
};
|
||||
|
||||
private:
|
||||
void onDefaultClick( wxCommandEvent& event ) override;
|
||||
void onGridDClick( wxGridEvent& event ) override;
|
||||
void onAddClick( wxCommandEvent& event ) override;
|
||||
void onEditClick( wxCommandEvent& event ) override;
|
||||
void onDeleteClick( wxCommandEvent& event ) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // PANEL_GIT_REPOS_H
|
|
@ -0,0 +1,167 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-254-gc2ef7767)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "widgets/std_bitmap_button.h"
|
||||
#include "widgets/wx_grid.h"
|
||||
|
||||
#include "panel_git_repos_base.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PANEL_GIT_REPOS_BASE::PANEL_GIT_REPOS_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : RESETTABLE_PANEL( parent, id, pos, size, style, name )
|
||||
{
|
||||
wxBoxSizer* bPanelSizer;
|
||||
bPanelSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxBoxSizer* bLeftSizer;
|
||||
bLeftSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_staticText12 = new wxStaticText( this, wxID_ANY, _("Git Commit Data"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText12->Wrap( -1 );
|
||||
bLeftSizer->Add( m_staticText12, 0, wxEXPAND|wxLEFT|wxTOP, 10 );
|
||||
|
||||
wxFlexGridSizer* fgSizer1;
|
||||
fgSizer1 = new wxFlexGridSizer( 0, 2, 0, 0 );
|
||||
fgSizer1->AddGrowableCol( 1 );
|
||||
fgSizer1->SetFlexibleDirection( wxBOTH );
|
||||
fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_cbDefault = new wxCheckBox( this, wxID_ANY, _("Use default values"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_cbDefault->SetValue(true);
|
||||
fgSizer1->Add( m_cbDefault, 0, wxALL, 5 );
|
||||
|
||||
|
||||
fgSizer1->Add( 0, 0, 0, wxEXPAND, 5 );
|
||||
|
||||
m_authorLabel = new wxStaticText( this, wxID_ANY, _("Author name:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_authorLabel->Wrap( -1 );
|
||||
m_authorLabel->Enable( false );
|
||||
|
||||
fgSizer1->Add( m_authorLabel, 0, wxALL, 5 );
|
||||
|
||||
m_author = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_author->Enable( false );
|
||||
|
||||
fgSizer1->Add( m_author, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_authorEmailLabel = new wxStaticText( this, wxID_ANY, _("Author e-mail:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_authorEmailLabel->Wrap( -1 );
|
||||
m_authorEmailLabel->Enable( false );
|
||||
|
||||
fgSizer1->Add( m_authorEmailLabel, 0, wxALL, 5 );
|
||||
|
||||
m_authorEmail = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_authorEmail->Enable( false );
|
||||
|
||||
fgSizer1->Add( m_authorEmail, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
bLeftSizer->Add( fgSizer1, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 13 );
|
||||
|
||||
m_staticline3 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
|
||||
bLeftSizer->Add( m_staticline3, 0, wxEXPAND|wxBOTTOM, 5 );
|
||||
|
||||
m_staticText20 = new wxStaticText( this, wxID_ANY, _("Git Repositories"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText20->Wrap( -1 );
|
||||
bLeftSizer->Add( m_staticText20, 0, wxEXPAND|wxLEFT|wxRIGHT, 13 );
|
||||
|
||||
wxBoxSizer* bAntialiasingSizer;
|
||||
bAntialiasingSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_grid = new WX_GRID( this, wxID_ANY, wxDefaultPosition, wxSize( 820,200 ), 0 );
|
||||
|
||||
// Grid
|
||||
m_grid->CreateGrid( 0, 10 );
|
||||
m_grid->EnableEditing( false );
|
||||
m_grid->EnableGridLines( true );
|
||||
m_grid->EnableDragGridSize( false );
|
||||
m_grid->SetMargins( 0, 0 );
|
||||
|
||||
// Columns
|
||||
m_grid->SetColSize( 0, 60 );
|
||||
m_grid->SetColSize( 1, 200 );
|
||||
m_grid->SetColSize( 2, 500 );
|
||||
m_grid->SetColSize( 3, 60 );
|
||||
m_grid->SetColSize( 4, 0 );
|
||||
m_grid->SetColSize( 5, 0 );
|
||||
m_grid->SetColSize( 6, 0 );
|
||||
m_grid->SetColSize( 7, 0 );
|
||||
m_grid->SetColSize( 8, 0 );
|
||||
m_grid->SetColSize( 9, 0 );
|
||||
m_grid->EnableDragColMove( false );
|
||||
m_grid->EnableDragColSize( true );
|
||||
m_grid->SetColLabelValue( 0, _("Active") );
|
||||
m_grid->SetColLabelValue( 1, _("Name") );
|
||||
m_grid->SetColLabelValue( 2, _("Path") );
|
||||
m_grid->SetColLabelValue( 3, _("Status") );
|
||||
m_grid->SetColLabelSize( 22 );
|
||||
m_grid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
|
||||
|
||||
// Rows
|
||||
m_grid->EnableDragRowSize( true );
|
||||
m_grid->SetRowLabelSize( 0 );
|
||||
m_grid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
|
||||
|
||||
// Label Appearance
|
||||
|
||||
// Cell Defaults
|
||||
m_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
|
||||
bAntialiasingSizer->Add( m_grid, 5, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
bLeftSizer->Add( bAntialiasingSizer, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
|
||||
|
||||
wxBoxSizer* bButtonsSizer;
|
||||
bButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_btnAddRepo = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
|
||||
m_btnAddRepo->SetToolTip( _("Add new repository") );
|
||||
|
||||
bButtonsSizer->Add( m_btnAddRepo, 0, wxALL, 5 );
|
||||
|
||||
m_btnEditRepo = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
|
||||
m_btnEditRepo->SetToolTip( _("Edit repository properties") );
|
||||
|
||||
bButtonsSizer->Add( m_btnEditRepo, 0, wxALL, 5 );
|
||||
|
||||
|
||||
bButtonsSizer->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_btnDelete = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
|
||||
m_btnDelete->SetToolTip( _("Remove Git Repository") );
|
||||
|
||||
bButtonsSizer->Add( m_btnDelete, 0, wxBOTTOM|wxRIGHT|wxTOP, 5 );
|
||||
|
||||
|
||||
bLeftSizer->Add( bButtonsSizer, 1, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
bPanelSizer->Add( bLeftSizer, 0, wxRIGHT, 20 );
|
||||
|
||||
|
||||
this->SetSizer( bPanelSizer );
|
||||
this->Layout();
|
||||
bPanelSizer->Fit( this );
|
||||
|
||||
// Connect Events
|
||||
m_cbDefault->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onDefaultClick ), NULL, this );
|
||||
m_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( PANEL_GIT_REPOS_BASE::onGridDClick ), NULL, this );
|
||||
m_btnAddRepo->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onAddClick ), NULL, this );
|
||||
m_btnEditRepo->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onEditClick ), NULL, this );
|
||||
m_btnDelete->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onDeleteClick ), NULL, this );
|
||||
}
|
||||
|
||||
PANEL_GIT_REPOS_BASE::~PANEL_GIT_REPOS_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
m_cbDefault->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onDefaultClick ), NULL, this );
|
||||
m_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( PANEL_GIT_REPOS_BASE::onGridDClick ), NULL, this );
|
||||
m_btnAddRepo->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onAddClick ), NULL, this );
|
||||
m_btnEditRepo->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onEditClick ), NULL, this );
|
||||
m_btnDelete->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_GIT_REPOS_BASE::onDeleteClick ), NULL, this );
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-254-gc2ef7767)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
class STD_BITMAP_BUTTON;
|
||||
class WX_GRID;
|
||||
|
||||
#include "widgets/resettable_panel.h"
|
||||
#include <wx/string.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/grid.h>
|
||||
#include <wx/bmpbuttn.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class PANEL_GIT_REPOS_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class PANEL_GIT_REPOS_BASE : public RESETTABLE_PANEL
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_staticText12;
|
||||
wxCheckBox* m_cbDefault;
|
||||
wxStaticText* m_authorLabel;
|
||||
wxTextCtrl* m_author;
|
||||
wxStaticText* m_authorEmailLabel;
|
||||
wxTextCtrl* m_authorEmail;
|
||||
wxStaticLine* m_staticline3;
|
||||
wxStaticText* m_staticText20;
|
||||
WX_GRID* m_grid;
|
||||
STD_BITMAP_BUTTON* m_btnAddRepo;
|
||||
STD_BITMAP_BUTTON* m_btnEditRepo;
|
||||
STD_BITMAP_BUTTON* m_btnDelete;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
virtual void onDefaultClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onGridDClick( wxGridEvent& event ) { event.Skip(); }
|
||||
virtual void onAddClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onEditClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onDeleteClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
PANEL_GIT_REPOS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
|
||||
|
||||
~PANEL_GIT_REPOS_BASE();
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,953 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="16" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">panel_git_repos_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">PanelGitRepos</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">1</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Panel" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">PANEL_GIT_REPOS_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">-1,-1</property>
|
||||
<property name="subclass">RESETTABLE_PANEL; widgets/resettable_panel.h; Not forward_declare</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bPanelSizer</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">20</property>
|
||||
<property name="flag">wxRIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bLeftSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxEXPAND|wxLEFT|wxTOP</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Git Commit Data</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText12</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">13</property>
|
||||
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxTOP</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxFlexGridSizer" expanded="1">
|
||||
<property name="cols">2</property>
|
||||
<property name="flexible_direction">wxBOTH</property>
|
||||
<property name="growablecols">1</property>
|
||||
<property name="growablerows"></property>
|
||||
<property name="hgap">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">fgSizer1</property>
|
||||
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="rows">0</property>
|
||||
<property name="vgap">0</property>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxCheckBox" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="checked">1</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Use default values</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_cbDefault</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnCheckBox">onDefaultClick</event>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="spacer" expanded="0">
|
||||
<property name="height">0</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="width">0</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">0</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Author name:</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_authorLabel</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxTextCtrl" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">0</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="maxlength"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_author</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">0</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Author e-mail:</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_authorEmailLabel</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxTextCtrl" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">0</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="maxlength"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_authorEmail</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND|wxBOTTOM</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticLine" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticline3</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxLI_HORIZONTAL</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">13</property>
|
||||
<property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Git Repositories</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText20</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND|wxLEFT|wxTOP</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bAntialiasingSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="0">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">5</property>
|
||||
<object class="wxGrid" expanded="0">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="autosize_cols">0</property>
|
||||
<property name="autosize_rows">0</property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="cell_bg"></property>
|
||||
<property name="cell_font"></property>
|
||||
<property name="cell_horiz_alignment">wxALIGN_LEFT</property>
|
||||
<property name="cell_text"></property>
|
||||
<property name="cell_vert_alignment">wxALIGN_TOP</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
|
||||
<property name="col_label_size">22</property>
|
||||
<property name="col_label_values">"Active" "Name" "Path" "Status"</property>
|
||||
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
|
||||
<property name="cols">10</property>
|
||||
<property name="column_sizes">60,200,500,60,0,0,0,0,0,0</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="drag_col_move">0</property>
|
||||
<property name="drag_col_size">1</property>
|
||||
<property name="drag_grid_size">0</property>
|
||||
<property name="drag_row_size">1</property>
|
||||
<property name="editing">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="grid_line_color"></property>
|
||||
<property name="grid_lines">1</property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label_bg"></property>
|
||||
<property name="label_font"></property>
|
||||
<property name="label_text"></property>
|
||||
<property name="margin_height">0</property>
|
||||
<property name="margin_width">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_grid</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="row_label_horiz_alignment">wxALIGN_CENTER</property>
|
||||
<property name="row_label_size">0</property>
|
||||
<property name="row_label_values"></property>
|
||||
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
|
||||
<property name="row_sizes"></property>
|
||||
<property name="rows">0</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size">820,200</property>
|
||||
<property name="subclass">WX_GRID; widgets/wx_grid.h; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnGridCellLeftDClick">onGridDClick</event>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bButtonsSizer</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBitmapButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="auth_needed">0</property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">MyButton</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_btnAddRepo</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip">Add new repository</property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnButtonClick">onAddClick</event>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBitmapButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="auth_needed">0</property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">MyButton</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_btnEditRepo</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip">Edit repository properties</property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnButtonClick">onEditClick</event>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="spacer" expanded="1">
|
||||
<property name="height">0</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="width">0</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxRIGHT|wxTOP</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBitmapButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="auth_needed">0</property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">MyButton</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_btnDelete</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip">Remove Git Repository</property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnButtonClick">onDeleteClick</event>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
|
@ -23,9 +23,11 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <bitmaps.h>
|
||||
#include <bitmap_store.h>
|
||||
#include <dialog_shim.h>
|
||||
#include <dialogs/git/panel_git_repos.h>
|
||||
#include <dialogs/panel_common_settings.h>
|
||||
#include <dialogs/panel_mouse_settings.h>
|
||||
#include <dialogs/panel_data_collection.h>
|
||||
|
@ -1071,6 +1073,15 @@ void EDA_BASE_FRAME::ShowPreferences( wxString aStartPage, wxString aStartParent
|
|||
|
||||
book->AddPage( hotkeysPanel, _( "Hotkeys" ) );
|
||||
|
||||
// This currently allows pre-defined repositories that we
|
||||
// don't use, so keep it disabled at the moment
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableGit && false )
|
||||
book->AddLazyPage(
|
||||
[]( wxWindow* aParent ) -> wxWindow*
|
||||
{
|
||||
return new PANEL_GIT_REPOS( aParent );
|
||||
}, _( "Version Control" ) );
|
||||
|
||||
#ifdef KICAD_USE_SENTRY
|
||||
book->AddLazyPage(
|
||||
[]( wxWindow* aParent ) -> wxWindow*
|
||||
|
|
|
@ -1721,6 +1721,129 @@ PLOT_DASH_TYPE EDA_SHAPE::GetLineStyle() const
|
|||
}
|
||||
|
||||
|
||||
bool EDA_SHAPE::operator==( const EDA_SHAPE& aOther ) const
|
||||
{
|
||||
if( GetShape() != aOther.GetShape() )
|
||||
return false;
|
||||
|
||||
if( m_fill != aOther.m_fill )
|
||||
return false;
|
||||
|
||||
if( m_stroke.GetWidth() != aOther.m_stroke.GetWidth() )
|
||||
return false;
|
||||
|
||||
if( m_stroke.GetPlotStyle() != aOther.m_stroke.GetPlotStyle() )
|
||||
return false;
|
||||
|
||||
if( m_fillColor != aOther.m_fillColor )
|
||||
return false;
|
||||
|
||||
if( m_start != aOther.m_start )
|
||||
return false;
|
||||
|
||||
if( m_end != aOther.m_end )
|
||||
return false;
|
||||
|
||||
if( m_arcCenter != aOther.m_arcCenter )
|
||||
return false;
|
||||
|
||||
if( m_bezierC1 != aOther.m_bezierC1 )
|
||||
return false;
|
||||
|
||||
if( m_bezierC2 != aOther.m_bezierC2 )
|
||||
return false;
|
||||
|
||||
if( m_bezierPoints != aOther.m_bezierPoints )
|
||||
return false;
|
||||
|
||||
for( int ii = 0; ii < m_poly.TotalVertices(); ++ii )
|
||||
{
|
||||
if( m_poly.CVertex( ii ) != aOther.m_poly.CVertex( ii ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double EDA_SHAPE::Similarity( const EDA_SHAPE& aOther ) const
|
||||
{
|
||||
if( GetShape() != aOther.GetShape() )
|
||||
return 0.0;
|
||||
|
||||
double similarity = 1.0;
|
||||
|
||||
if( m_fill != aOther.m_fill )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_stroke.GetWidth() != aOther.m_stroke.GetWidth() )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_stroke.GetPlotStyle() != aOther.m_stroke.GetPlotStyle() )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_fillColor != aOther.m_fillColor )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_start != aOther.m_start )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_end != aOther.m_end )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_arcCenter != aOther.m_arcCenter )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_bezierC1 != aOther.m_bezierC1 )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_bezierC2 != aOther.m_bezierC2 )
|
||||
similarity *= 0.9;
|
||||
|
||||
{
|
||||
int m = m_bezierPoints.size();
|
||||
int n = aOther.m_bezierPoints.size();
|
||||
|
||||
size_t longest = alg::longest_common_subset( m_bezierPoints, aOther.m_bezierPoints );
|
||||
|
||||
similarity *= std::pow( 0.9, m + n - 2 * longest );
|
||||
}
|
||||
|
||||
{
|
||||
int m = m_poly.TotalVertices();
|
||||
int n = aOther.m_poly.TotalVertices();
|
||||
std::vector<VECTOR2I> poly;
|
||||
std::vector<VECTOR2I> otherPoly;
|
||||
VECTOR2I lastPt( 0, 0 );
|
||||
|
||||
// We look for the longest common subset of the two polygons, but we need to
|
||||
// offset each point because we're actually looking for overall similarity, not just
|
||||
// exact matches. So if the zone is moved by 1IU, we only want one point to be
|
||||
// considered "moved" rather than the entire polygon. In this case, the first point
|
||||
// will not be a match but the rest of the sequence will.
|
||||
for( int ii = 0; ii < m; ++ii )
|
||||
{
|
||||
poly.emplace_back( lastPt - m_poly.CVertex( ii ) );
|
||||
lastPt = m_poly.CVertex( ii );
|
||||
}
|
||||
|
||||
lastPt = VECTOR2I( 0, 0 );
|
||||
|
||||
for( int ii = 0; ii < n; ++ii )
|
||||
{
|
||||
otherPoly.emplace_back( lastPt - aOther.m_poly.CVertex( ii ) );
|
||||
lastPt = aOther.m_poly.CVertex( ii );
|
||||
}
|
||||
|
||||
size_t longest = alg::longest_common_subset( poly, otherPoly );
|
||||
|
||||
similarity *= std::pow( 0.9, m + n - 2 * longest );
|
||||
}
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_ENUM_TO_WXANY( SHAPE_T )
|
||||
IMPLEMENT_ENUM_TO_WXANY( PLOT_DASH_TYPE )
|
||||
|
||||
|
|
|
@ -1025,6 +1025,67 @@ bool EDA_TEXT::ValidateHyperlink( const wxString& aURL )
|
|||
return false;
|
||||
}
|
||||
|
||||
double EDA_TEXT::Levenshtein( const EDA_TEXT& aOther ) const
|
||||
{
|
||||
// Compute the Levenshtein distance between the two strings
|
||||
const wxString& str1 = GetText();
|
||||
const wxString& str2 = aOther.GetText();
|
||||
|
||||
int m = str1.length();
|
||||
int n = str2.length();
|
||||
|
||||
if( n == 0 || m == 0 )
|
||||
return 0.0;
|
||||
|
||||
// Create a matrix to store the distance values
|
||||
std::vector<std::vector<int>> distance(m + 1, std::vector<int>(n + 1));
|
||||
|
||||
// Initialize the matrix
|
||||
for( int i = 0; i <= m; i++ )
|
||||
distance[i][0] = i;
|
||||
for( int j = 0; j <= n; j++ )
|
||||
distance[0][j] = j;
|
||||
|
||||
// Calculate the distance
|
||||
for( int i = 1; i <= m; i++ )
|
||||
{
|
||||
for( int j = 1; j <= n; j++ )
|
||||
{
|
||||
if( str1[i - 1] == str2[j - 1] )
|
||||
{
|
||||
distance[i][j] = distance[i - 1][j - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
distance[i][j] = std::min( { distance[i - 1][j], distance[i][j - 1],
|
||||
distance[i - 1][j - 1] } ) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate similarity score
|
||||
int maxLen = std::max( m, n );
|
||||
double similarity = 1.0 - ( static_cast<double>( distance[m][n] ) / maxLen );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
double EDA_TEXT::Similarity( const EDA_TEXT& aOther ) const
|
||||
{
|
||||
double retval = 1.0;
|
||||
|
||||
if( !( m_attributes == aOther.m_attributes ) )
|
||||
retval *= 0.9;
|
||||
|
||||
if( m_pos != aOther.m_pos )
|
||||
retval *= 0.9;
|
||||
|
||||
retval *= Levenshtein( aOther );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_TEXT::IsGotoPageHref( const wxString& aHref, wxString* aDestination )
|
||||
{
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include <launch_ext.h>
|
||||
#include "wx/tokenzr.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
void QuoteString( wxString& string )
|
||||
{
|
||||
if( !string.StartsWith( wxT( "\"" ) ) )
|
||||
|
@ -292,3 +294,51 @@ wxString QuoteFullPath( wxFileName& fn, wxPathFormat format )
|
|||
{
|
||||
return wxT( "\"" ) + fn.GetFullPath( format ) + wxT( "\"" );
|
||||
}
|
||||
|
||||
|
||||
bool RmDirRecursive( const wxString& aFileName, wxString* aErrors )
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::string rmDir = aFileName.ToStdString();
|
||||
|
||||
if( rmDir.length() < 3 )
|
||||
{
|
||||
if( aErrors )
|
||||
*aErrors = _( "Invalid directory name, cannot remove root" );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !fs::exists( rmDir ) )
|
||||
{
|
||||
if( aErrors )
|
||||
*aErrors = wxString::Format( _( "Directory '%s' does not exist" ), aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::path path( rmDir );
|
||||
|
||||
if( !fs::is_directory( path ) )
|
||||
{
|
||||
if( aErrors )
|
||||
*aErrors = wxString::Format( _( "'%s' is not a directory" ), aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fs::remove_all( path );
|
||||
}
|
||||
catch( const fs::filesystem_error& e )
|
||||
{
|
||||
if( aErrors )
|
||||
*aErrors = wxString::Format( _( "Error removing directory '%s': %s" ), aFileName, e.what() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_add_to_index_handler.h"
|
||||
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
GIT_ADD_TO_INDEX_HANDLER::GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository )
|
||||
{
|
||||
m_repository = aRepository;
|
||||
m_filesToAdd.clear();
|
||||
}
|
||||
|
||||
GIT_ADD_TO_INDEX_HANDLER::~GIT_ADD_TO_INDEX_HANDLER()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool GIT_ADD_TO_INDEX_HANDLER::AddToIndex( const wxString& aFilePath )
|
||||
{
|
||||
// Test if file is currently in the index
|
||||
|
||||
git_index* index = nullptr;
|
||||
size_t at_pos = 0;
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_index_find( &at_pos, index, aFilePath.ToUTF8().data() );
|
||||
|
||||
if( at_pos >= 0)
|
||||
{
|
||||
git_index_free( index );
|
||||
wxLogError( "%s already in index", aFilePath );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_index_free( index );
|
||||
|
||||
// Add file to index if not already there
|
||||
m_filesToAdd.push_back( aFilePath );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GIT_ADD_TO_INDEX_HANDLER::PerformAddToIndex()
|
||||
{
|
||||
git_index* index = nullptr;
|
||||
|
||||
m_filesFailedToAdd.clear();
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
std::copy( m_filesToAdd.begin(), m_filesToAdd.end(), std::back_inserter( m_filesFailedToAdd ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
for( auto& file : m_filesToAdd )
|
||||
{
|
||||
if( git_index_add_bypath( index, file.ToUTF8().data() ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to add %s to index", file );
|
||||
m_filesFailedToAdd.push_back( file );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( git_index_write( index ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to write index" );
|
||||
m_filesFailedToAdd.clear();
|
||||
std::copy( m_filesToAdd.begin(), m_filesToAdd.end(), std::back_inserter( m_filesFailedToAdd ) );
|
||||
git_index_free( index );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_index_free( index );
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_ADD_TO_INDEX_HANDLER_H_
|
||||
#define GIT_ADD_TO_INDEX_HANDLER_H_
|
||||
|
||||
#include <git2.h>
|
||||
#include <vector>
|
||||
|
||||
class wxString;
|
||||
|
||||
class GIT_ADD_TO_INDEX_HANDLER
|
||||
{
|
||||
public:
|
||||
GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository );
|
||||
virtual ~GIT_ADD_TO_INDEX_HANDLER();
|
||||
|
||||
bool AddToIndex( const wxString& aFilePath );
|
||||
|
||||
bool PerformAddToIndex();
|
||||
|
||||
private:
|
||||
|
||||
git_repository* m_repository;
|
||||
|
||||
std::vector<wxString> m_filesToAdd;
|
||||
std::vector<wxString> m_filesFailedToAdd;
|
||||
};
|
||||
|
||||
#endif /* GIT_ADD_TO_INDEX_HANDLER_H_ */
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_clone_handler.h"
|
||||
|
||||
#include <git/kicad_git_common.h>
|
||||
|
||||
#include <git2.h>
|
||||
#include <wx/filename.h>
|
||||
|
||||
GIT_CLONE_HANDLER::GIT_CLONE_HANDLER() : KIGIT_COMMON( nullptr )
|
||||
{}
|
||||
|
||||
GIT_CLONE_HANDLER::~GIT_CLONE_HANDLER()
|
||||
{
|
||||
if( m_repo )
|
||||
git_repository_free( m_repo );
|
||||
}
|
||||
|
||||
|
||||
bool GIT_CLONE_HANDLER::PerformClone()
|
||||
{
|
||||
wxFileName clonePath( m_clonePath );
|
||||
|
||||
if( !clonePath.DirExists() )
|
||||
{
|
||||
if( !clonePath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not create directory '%s'" ), m_clonePath ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
git_clone_options cloneOptions = GIT_CLONE_OPTIONS_INIT;
|
||||
cloneOptions.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
cloneOptions.checkout_opts.progress_cb = clone_progress_cb;
|
||||
cloneOptions.checkout_opts.progress_payload = this;
|
||||
cloneOptions.fetch_opts.callbacks.transfer_progress = transfer_progress_cb;
|
||||
cloneOptions.fetch_opts.callbacks.credentials = credentials_cb;
|
||||
cloneOptions.fetch_opts.callbacks.payload = this;
|
||||
|
||||
m_testedTypes = 0;
|
||||
|
||||
if( git_clone( &m_repo, m_URL.ToStdString().c_str(), m_clonePath.ToStdString().c_str(), &cloneOptions ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not clone repository '%s'" ), m_URL ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_progressReporter )
|
||||
m_progressReporter->Hide();
|
||||
|
||||
m_previousProgress = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GIT_CLONE_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
{
|
||||
ReportProgress( aCurrent, aTotal, aMessage );
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_CLONE_HANDLER_H_
|
||||
#define GIT_CLONE_HANDLER_H_
|
||||
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/git_progress.h>
|
||||
class GIT_CLONE_HANDLER : public KIGIT_COMMON, public GIT_PROGRESS
|
||||
{
|
||||
public:
|
||||
GIT_CLONE_HANDLER();
|
||||
~GIT_CLONE_HANDLER();
|
||||
|
||||
bool PerformClone();
|
||||
|
||||
void SetURL( const wxString& aURL ) { m_URL = aURL; }
|
||||
wxString GetURL() const { return m_URL; }
|
||||
|
||||
void SetBranch( const wxString& aBranch ) { m_branch = aBranch; }
|
||||
wxString GetBranch() const { return m_branch; }
|
||||
|
||||
void SetClonePath( const wxString& aPath ) { m_clonePath = aPath; }
|
||||
wxString GetClonePath() const { return m_clonePath; }
|
||||
|
||||
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
|
||||
|
||||
private:
|
||||
|
||||
wxString m_URL;
|
||||
wxString m_branch;
|
||||
wxString m_clonePath;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_commit_handler.h"
|
||||
|
||||
GIT_COMMIT_HANDLER::GIT_COMMIT_HANDLER( git_repository* aRepo ) :
|
||||
KIGIT_COMMON( aRepo )
|
||||
{}
|
||||
|
||||
GIT_COMMIT_HANDLER::~GIT_COMMIT_HANDLER()
|
||||
{}
|
||||
|
||||
|
||||
GIT_COMMIT_HANDLER::CommitResult GIT_COMMIT_HANDLER::PerformCommit( const std::vector<std::string>& aFilesToCommit )
|
||||
{
|
||||
|
||||
return CommitResult::Success;
|
||||
}
|
||||
|
||||
std::string GIT_COMMIT_HANDLER::GetErrorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
void GIT_COMMIT_HANDLER::AddErrorString( const std::string& aErrorString )
|
||||
{
|
||||
m_errorString += aErrorString;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_COMMIT_HANDLER_H
|
||||
#define GIT_COMMIT_HANDLER_H
|
||||
|
||||
// Define a class to handle git commit operations
|
||||
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git2.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class GIT_COMMIT_HANDLER : public KIGIT_COMMON
|
||||
{
|
||||
public:
|
||||
GIT_COMMIT_HANDLER( git_repository* aRepo );
|
||||
virtual ~GIT_COMMIT_HANDLER();
|
||||
|
||||
enum class CommitResult
|
||||
{
|
||||
Success,
|
||||
Error,
|
||||
Cancelled
|
||||
};
|
||||
|
||||
CommitResult PerformCommit( const std::vector<std::string>& aFilesToCommit );
|
||||
|
||||
std::string GetErrorString() const;
|
||||
|
||||
private:
|
||||
void AddErrorString( const std::string& aErrorString );
|
||||
|
||||
std::string m_errorString;
|
||||
};
|
||||
|
||||
#endif // GIT_COMMIT_HANDLER_H
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_PROGRESS_H_
|
||||
#define GIT_PROGRESS_H_
|
||||
|
||||
#include <widgets/wx_progress_reporters.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class GIT_PROGRESS
|
||||
{
|
||||
public:
|
||||
GIT_PROGRESS() : m_previousProgress( 0 )
|
||||
{
|
||||
m_progressReporter.reset();
|
||||
}
|
||||
|
||||
|
||||
void SetProgressReporter( std::unique_ptr<WX_PROGRESS_REPORTER> aProgressReporter )
|
||||
{
|
||||
m_progressReporter = std::move( aProgressReporter );
|
||||
}
|
||||
|
||||
void ReportProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
{
|
||||
|
||||
if( m_progressReporter )
|
||||
{
|
||||
if( aCurrent == m_previousProgress || aTotal == 0 )
|
||||
{
|
||||
m_progressReporter->Pulse( aMessage );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_progressReporter->SetCurrentProgress( static_cast<double>( aCurrent ) / aTotal );
|
||||
m_progressReporter->Report( aMessage );
|
||||
}
|
||||
|
||||
m_previousProgress = aCurrent;
|
||||
m_progressReporter->KeepRefreshing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
int m_previousProgress;
|
||||
|
||||
std::unique_ptr<WX_PROGRESS_REPORTER> m_progressReporter;
|
||||
};
|
||||
|
||||
#endif // GIT_PROGRESS_H__
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_pull_handler.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
GIT_PULL_HANDLER::GIT_PULL_HANDLER( git_repository* aRepo ) : KIGIT_COMMON( aRepo )
|
||||
{}
|
||||
|
||||
GIT_PULL_HANDLER::~GIT_PULL_HANDLER()
|
||||
{}
|
||||
|
||||
|
||||
bool GIT_PULL_HANDLER::PerformFetch()
|
||||
{
|
||||
// Fetch updates from remote repository
|
||||
git_remote* remote = nullptr;
|
||||
|
||||
if( git_remote_lookup( &remote, m_repo, "origin" ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not lookup remote '%s'" ), "origin" ).ToStdString() );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_remote_callbacks remoteCallbacks = GIT_REMOTE_CALLBACKS_INIT;
|
||||
remoteCallbacks.sideband_progress = progress_cb;
|
||||
remoteCallbacks.transfer_progress = transfer_progress_cb;
|
||||
remoteCallbacks.credentials = credentials_cb;
|
||||
remoteCallbacks.payload = this;
|
||||
|
||||
if( git_remote_connect( remote, GIT_DIRECTION_FETCH, &remoteCallbacks, nullptr, nullptr ) )
|
||||
{
|
||||
git_remote_free( remote );
|
||||
AddErrorString( wxString::Format( _( "Could not connect to remote '%s'" ), "origin" ).ToStdString() );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_fetch_options fetchOptions = GIT_FETCH_OPTIONS_INIT;
|
||||
fetchOptions.callbacks = remoteCallbacks;
|
||||
|
||||
if( git_remote_fetch( remote, nullptr, &fetchOptions, nullptr ) )
|
||||
{
|
||||
git_remote_free( remote );
|
||||
AddErrorString( wxString::Format( _( "Could not fetch data from remote '%s'" ), "origin" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_remote_free( remote );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PullResult GIT_PULL_HANDLER::PerformPull()
|
||||
{
|
||||
PullResult result = PullResult::Success;
|
||||
|
||||
if( !PerformFetch() )
|
||||
return PullResult::Error;
|
||||
|
||||
git_oid pull_merge_oid = {};
|
||||
|
||||
if( git_repository_fetchhead_foreach( m_repo, fetchhead_foreach_cb, &pull_merge_oid ) )
|
||||
{
|
||||
AddErrorString( _( "Could not read 'FETCH_HEAD'" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
git_annotated_commit* fetchhead_commit;
|
||||
|
||||
if( git_annotated_commit_lookup( &fetchhead_commit, m_repo, &pull_merge_oid ) )
|
||||
{
|
||||
AddErrorString( _( "Could not lookup commit" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
const git_annotated_commit* merge_commits[] = { fetchhead_commit };
|
||||
git_merge_analysis_t merge_analysis;
|
||||
git_merge_preference_t merge_preference = GIT_MERGE_PREFERENCE_NONE;
|
||||
|
||||
if( git_merge_analysis( &merge_analysis, &merge_preference, m_repo, merge_commits, 1 ) )
|
||||
{
|
||||
AddErrorString( _( "Could not analyze merge" ) );
|
||||
git_annotated_commit_free( fetchhead_commit );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
if( !( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL ) )
|
||||
git_annotated_commit_free( fetchhead_commit );
|
||||
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_UNBORN )
|
||||
{
|
||||
AddErrorString( _( "Invalid HEAD. Cannot merge." ) );
|
||||
return PullResult::MergeFailed;
|
||||
}
|
||||
|
||||
// Nothing to do if the repository is up to date
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE )
|
||||
{
|
||||
git_repository_state_cleanup( m_repo );
|
||||
return PullResult::UpToDate;
|
||||
}
|
||||
|
||||
// Fast-forward is easy, just update the local reference
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD )
|
||||
{
|
||||
return handleFastForward();
|
||||
}
|
||||
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL )
|
||||
{
|
||||
PullResult ret = handleMerge( merge_commits, 1 );
|
||||
git_annotated_commit_free( fetchhead_commit );
|
||||
return ret;
|
||||
}
|
||||
|
||||
//TODO: handle merges when they need to be resolved
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, std::vector<CommitDetails>>>& GIT_PULL_HANDLER::GetFetchResults() const {
|
||||
return m_fetchResults;
|
||||
}
|
||||
|
||||
std::string GIT_PULL_HANDLER::getFirstLineFromCommitMessage( const std::string& aMessage )
|
||||
{
|
||||
size_t firstLineEnd = aMessage.find_first_of( '\n' );
|
||||
|
||||
if( firstLineEnd != std::string::npos )
|
||||
return aMessage.substr( 0, firstLineEnd );
|
||||
|
||||
return aMessage;
|
||||
}
|
||||
|
||||
std::string GIT_PULL_HANDLER::getFormattedCommitDate( const git_time& aTime )
|
||||
{
|
||||
char dateBuffer[64];
|
||||
strftime( dateBuffer, sizeof( dateBuffer ), "%Y-%b-%d %H:%M:%S", gmtime( &aTime.time ) );
|
||||
return dateBuffer;
|
||||
}
|
||||
|
||||
|
||||
PullResult GIT_PULL_HANDLER::handleFastForward()
|
||||
{
|
||||
// Update local references with fetched data
|
||||
git_reference* updatedRef = nullptr;
|
||||
|
||||
if( git_repository_head( &updatedRef, m_repo ) )
|
||||
{
|
||||
AddErrorString( _( "Could not get repository head" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
const char* updatedRefName = git_reference_name( updatedRef );
|
||||
git_reference_free( updatedRef );
|
||||
|
||||
git_oid updatedRefOid;
|
||||
if( git_reference_name_to_id( &updatedRefOid, m_repo, updatedRefName ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not get reference OID for reference '%s'" ), updatedRefName ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
git_checkout_options checkoutOptions = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
checkoutOptions.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
if( git_checkout_head( m_repo, &checkoutOptions ) )
|
||||
{
|
||||
AddErrorString( _( "Failed to perform checkout operation." ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
// Collect commit details for updated references
|
||||
git_revwalk* revWalker = nullptr;
|
||||
git_revwalk_new( &revWalker, m_repo );
|
||||
git_revwalk_sorting( revWalker, GIT_SORT_TIME );
|
||||
git_revwalk_push_glob( revWalker, updatedRefName );
|
||||
|
||||
git_oid commitOid;
|
||||
while( git_revwalk_next( &commitOid, revWalker ) == 0 )
|
||||
{
|
||||
git_commit* commit = nullptr;
|
||||
|
||||
if( git_commit_lookup( &commit, m_repo, &commitOid ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not lookup commit '{}'" ), git_oid_tostr_s( &commitOid ) ) );
|
||||
git_revwalk_free( revWalker );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
CommitDetails details;
|
||||
details.m_sha = git_oid_tostr_s( &commitOid );
|
||||
details.m_firstLine = getFirstLineFromCommitMessage( git_commit_message( commit ) );
|
||||
details.m_author = git_commit_author( commit )->name;
|
||||
details.m_date = getFormattedCommitDate( git_commit_author( commit )->when );
|
||||
|
||||
std::pair<std::string, std::vector<CommitDetails>>& branchCommits =
|
||||
m_fetchResults.emplace_back();
|
||||
branchCommits.first = updatedRefName;
|
||||
branchCommits.second.push_back( details );
|
||||
|
||||
//TODO: log these to the parent
|
||||
git_commit_free( commit );
|
||||
}
|
||||
|
||||
git_revwalk_free( revWalker );
|
||||
|
||||
git_repository_state_cleanup( m_repo );
|
||||
return PullResult::FastForward;
|
||||
}
|
||||
|
||||
|
||||
PullResult GIT_PULL_HANDLER::handleMerge( const git_annotated_commit** aMergeHeads,
|
||||
size_t aMergeHeadsCount )
|
||||
{
|
||||
git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT;
|
||||
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
|
||||
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
|
||||
if( git_merge( m_repo, aMergeHeads, aMergeHeadsCount, &merge_opts, &checkout_opts ) )
|
||||
{
|
||||
AddErrorString( _( "Could not merge commits" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
// Get the repository index
|
||||
git_index* index;
|
||||
if( git_repository_index( &index, m_repo ) )
|
||||
{
|
||||
AddErrorString( _( "Could not get repository index" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
// Check for conflicts
|
||||
git_index_conflict_iterator* conflicts;
|
||||
if( git_index_conflict_iterator_new( &conflicts, index ) )
|
||||
{
|
||||
AddErrorString( _( "Could not get conflict iterator" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
const git_index_entry* ancestor;
|
||||
const git_index_entry* our;
|
||||
const git_index_entry* their;
|
||||
std::vector<ConflictData> conflict_data;
|
||||
|
||||
while( git_index_conflict_next( &ancestor, &our, &their, conflicts ) == 0 )
|
||||
{
|
||||
// Case 3: Both files have changed
|
||||
if( ancestor && our && their )
|
||||
{
|
||||
ConflictData conflict_datum;
|
||||
conflict_datum.filename = our->path;
|
||||
conflict_datum.our_oid = our->id;
|
||||
conflict_datum.their_oid = their->id;
|
||||
conflict_datum.our_commit_time = our->mtime.seconds;
|
||||
conflict_datum.their_commit_time = their->mtime.seconds;
|
||||
conflict_datum.our_status = _( "Changed" );
|
||||
conflict_datum.their_status = _( "Changed" );
|
||||
|
||||
conflict_data.push_back( conflict_datum );
|
||||
}
|
||||
// Case 4: File added in both ours and theirs
|
||||
else if( !ancestor && our && their )
|
||||
{
|
||||
ConflictData conflict_datum;
|
||||
conflict_datum.filename = our->path;
|
||||
conflict_datum.our_oid = our->id;
|
||||
conflict_datum.their_oid = their->id;
|
||||
conflict_datum.our_commit_time = our->mtime.seconds;
|
||||
conflict_datum.their_commit_time = their->mtime.seconds;
|
||||
conflict_datum.our_status = _( "Added" );
|
||||
conflict_datum.their_status = _( "Added" );
|
||||
|
||||
conflict_data.push_back( conflict_datum );
|
||||
}
|
||||
// Case 1: Remote file has changed or been added, local file has not
|
||||
else if( their && !our )
|
||||
{
|
||||
// Accept their changes
|
||||
git_index_add( index, their );
|
||||
}
|
||||
// Case 2: Local file has changed or been added, remote file has not
|
||||
else if( our && !their )
|
||||
{
|
||||
// Accept our changes
|
||||
git_index_add( index, our );
|
||||
}
|
||||
else
|
||||
{
|
||||
ConflictData conflict_datum;
|
||||
conflict_datum.filename = our->path;
|
||||
conflict_datum.our_oid = our->id;
|
||||
conflict_datum.their_oid = their->id;
|
||||
conflict_datum.our_commit_time = our->mtime.seconds;
|
||||
conflict_datum.their_commit_time = their->mtime.seconds;
|
||||
conflict_datum.our_status = _( "Other" );
|
||||
conflict_datum.their_status = _( "Other" );
|
||||
|
||||
conflict_data.push_back( conflict_datum );
|
||||
}
|
||||
}
|
||||
|
||||
if( conflict_data.empty() )
|
||||
{
|
||||
git_index_conflict_cleanup( index );
|
||||
git_index_write( index );
|
||||
}
|
||||
|
||||
git_index_conflict_iterator_free( conflicts );
|
||||
git_index_free( index );
|
||||
|
||||
return conflict_data.empty() ? PullResult::Success : PullResult::MergeFailed;
|
||||
}
|
||||
|
||||
|
||||
void GIT_PULL_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
{
|
||||
ReportProgress( aCurrent, aTotal, aMessage );
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GITPULLHANDLER_HPP
|
||||
#define GITPULLHANDLER_HPP
|
||||
|
||||
#include <git2.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "kicad_git_common.h"
|
||||
|
||||
#include <git/git_progress.h>
|
||||
|
||||
// Structure to store commit details
|
||||
struct CommitDetails
|
||||
{
|
||||
std::string m_sha;
|
||||
std::string m_firstLine;
|
||||
std::string m_author;
|
||||
std::string m_date;
|
||||
};
|
||||
|
||||
// Enum for result codes
|
||||
enum class PullResult
|
||||
{
|
||||
Success,
|
||||
Error,
|
||||
UpToDate,
|
||||
FastForward,
|
||||
MergeFailed
|
||||
};
|
||||
|
||||
struct ConflictData
|
||||
{
|
||||
std::string filename;
|
||||
std::string our_status;
|
||||
std::string their_status;
|
||||
git_oid our_oid;
|
||||
git_oid their_oid;
|
||||
git_time_t our_commit_time;
|
||||
git_time_t their_commit_time;
|
||||
bool use_ours; // Flag indicating user's choice (true = ours, false = theirs)
|
||||
};
|
||||
|
||||
|
||||
class GIT_PULL_HANDLER : public KIGIT_COMMON, public GIT_PROGRESS
|
||||
{
|
||||
public:
|
||||
GIT_PULL_HANDLER( git_repository* aRepo );
|
||||
~GIT_PULL_HANDLER();
|
||||
|
||||
PullResult PerformPull();
|
||||
|
||||
bool PerformFetch();
|
||||
|
||||
const std::vector<std::pair<std::string, std::vector<CommitDetails>>>& GetFetchResults() const;
|
||||
|
||||
// Set the callback function for conflict resolution
|
||||
void SetConflictCallback(
|
||||
std::function<int( std::vector<ConflictData>& aConflicts )> aCallback )
|
||||
{
|
||||
m_conflictCallback = aCallback;
|
||||
}
|
||||
|
||||
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
|
||||
|
||||
private:
|
||||
std::string getFirstLineFromCommitMessage( const std::string& aMessage );
|
||||
std::string getFormattedCommitDate( const git_time& aTime );private:
|
||||
|
||||
PullResult handleFastForward();
|
||||
PullResult handleMerge( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount);
|
||||
|
||||
std::vector<std::pair<std::string, std::vector<CommitDetails>>> m_fetchResults;
|
||||
std::function<int( std::vector<ConflictData>& aConflicts )> m_conflictCallback;
|
||||
};
|
||||
|
||||
#endif // GITPULLHANDLER_HPP
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_push_handler.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
GIT_PUSH_HANDLER::GIT_PUSH_HANDLER( git_repository* aRepo ) : KIGIT_COMMON( aRepo )
|
||||
{}
|
||||
|
||||
GIT_PUSH_HANDLER::~GIT_PUSH_HANDLER()
|
||||
{}
|
||||
|
||||
PushResult GIT_PUSH_HANDLER::PerformPush()
|
||||
{
|
||||
PushResult result = PushResult::Success;
|
||||
|
||||
// Fetch updates from remote repository
|
||||
git_remote* remote = nullptr;
|
||||
|
||||
if( git_remote_lookup( &remote, m_repo, "origin" ) != 0 )
|
||||
{
|
||||
AddErrorString( _( "Could not lookup remote" ) );
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
git_remote_callbacks remoteCallbacks = GIT_REMOTE_CALLBACKS_INIT;
|
||||
remoteCallbacks.sideband_progress = progress_cb;
|
||||
remoteCallbacks.transfer_progress = transfer_progress_cb;
|
||||
remoteCallbacks.update_tips = update_cb;
|
||||
remoteCallbacks.push_transfer_progress = push_transfer_progress_cb;
|
||||
remoteCallbacks.payload = this;
|
||||
|
||||
if( git_remote_connect( remote, GIT_DIRECTION_PUSH, &remoteCallbacks, nullptr, nullptr ) )
|
||||
{
|
||||
git_remote_free( remote );
|
||||
AddErrorString( _( "Could not connect to remote" ) );
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
git_push_options pushOptions = GIT_PUSH_OPTIONS_INIT;
|
||||
pushOptions.callbacks = remoteCallbacks;
|
||||
|
||||
if( git_remote_push( remote, nullptr, &pushOptions ) )
|
||||
{
|
||||
git_remote_free( remote );
|
||||
AddErrorString( _( "Could not push to remote" ) );
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void GIT_PUSH_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
{
|
||||
ReportProgress( aCurrent, aTotal, aMessage );
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GITPUSHHANDLER_HPP
|
||||
#define GITPUSHHANDLER_HPP
|
||||
|
||||
#include <git2.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "kicad_git_common.h"
|
||||
#include <git/git_progress.h>
|
||||
|
||||
// Enum for result codes
|
||||
enum class PushResult
|
||||
{
|
||||
Success,
|
||||
Error,
|
||||
UpToDate
|
||||
};
|
||||
|
||||
class GIT_PUSH_HANDLER : public KIGIT_COMMON, public GIT_PROGRESS
|
||||
{
|
||||
public:
|
||||
GIT_PUSH_HANDLER( git_repository* aRepo );
|
||||
~GIT_PUSH_HANDLER();
|
||||
|
||||
PushResult PerformPush();
|
||||
|
||||
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // GITPUSHHANDLER_HPP
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "git_remove_from_index_handler.h"
|
||||
|
||||
GIT_REMOVE_FROM_INDEX_HANDLER::GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository )
|
||||
{
|
||||
m_repository = aRepository;
|
||||
m_filesToRemove.clear();
|
||||
}
|
||||
|
||||
GIT_REMOVE_FROM_INDEX_HANDLER::~GIT_REMOVE_FROM_INDEX_HANDLER()
|
||||
{
|
||||
}
|
||||
|
||||
bool GIT_REMOVE_FROM_INDEX_HANDLER::RemoveFromIndex( const wxString& aFilePath )
|
||||
{
|
||||
// Test if file is currently in the index
|
||||
|
||||
git_index* index = nullptr;
|
||||
size_t at_pos = 0;
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( git_index_find( &at_pos, index, aFilePath.ToUTF8().data() ) != 0 )
|
||||
{
|
||||
git_index_free( index );
|
||||
wxLogError( "Failed to find index entry for %s", aFilePath );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_index_free( index );
|
||||
|
||||
m_filesToRemove.push_back( aFilePath );
|
||||
return true;
|
||||
}
|
||||
|
||||
void GIT_REMOVE_FROM_INDEX_HANDLER::PerformRemoveFromIndex()
|
||||
{
|
||||
for( auto& file : m_filesToRemove )
|
||||
{
|
||||
git_index* index = nullptr;
|
||||
git_oid oid;
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( git_index_remove_bypath( index, file.ToUTF8().data() ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to remove index entry for %s", file );
|
||||
return;
|
||||
}
|
||||
|
||||
if( git_index_write( index ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to write index" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( git_index_write_tree( &oid, index ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to write index tree" );
|
||||
return;
|
||||
}
|
||||
|
||||
git_index_free( index );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_REMOVE_FROM_INDEX_HANDLER_H_
|
||||
#define GIT_REMOVE_FROM_INDEX_HANDLER_H_
|
||||
|
||||
#include <git2.h>
|
||||
#include <vector>
|
||||
|
||||
class wxString;
|
||||
|
||||
class GIT_REMOVE_FROM_INDEX_HANDLER
|
||||
{
|
||||
public:
|
||||
GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository );
|
||||
virtual ~GIT_REMOVE_FROM_INDEX_HANDLER();
|
||||
|
||||
bool RemoveFromIndex( const wxString& aFilePath );
|
||||
|
||||
void PerformRemoveFromIndex();
|
||||
|
||||
private:
|
||||
|
||||
git_repository* m_repository;
|
||||
|
||||
std::vector<wxString> m_filesToRemove;
|
||||
};
|
||||
|
||||
|
||||
#endif /* GIT_REMOVE_FROM_INDEX_HANDLER_H_ */
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_resolve_conflict_handler.h"
|
||||
|
||||
GIT_RESOLVE_CONFLICT_HANDLER::GIT_RESOLVE_CONFLICT_HANDLER( git_repository* aRepository )
|
||||
{
|
||||
m_repository = aRepository;
|
||||
}
|
||||
|
||||
GIT_RESOLVE_CONFLICT_HANDLER::~GIT_RESOLVE_CONFLICT_HANDLER()
|
||||
{
|
||||
}
|
||||
|
||||
bool GIT_RESOLVE_CONFLICT_HANDLER::PerformResolveConflict()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_RESOLVE_CONFLICT_HANDLER_H
|
||||
#define GIT_RESOLVE_CONFLICT_HANDLER_H
|
||||
|
||||
#include <git2.h>
|
||||
|
||||
class wxString;
|
||||
|
||||
class GIT_RESOLVE_CONFLICT_HANDLER
|
||||
{
|
||||
public:
|
||||
GIT_RESOLVE_CONFLICT_HANDLER( git_repository* aRepository );
|
||||
virtual ~GIT_RESOLVE_CONFLICT_HANDLER();
|
||||
|
||||
bool PerformResolveConflict();
|
||||
|
||||
private:
|
||||
git_repository* m_repository;
|
||||
};
|
||||
|
||||
#endif // GIT_RESOLVE_CONFLICT_HANDLER_H
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_revert_handler.h"
|
||||
|
||||
#include <wx/log.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
GIT_REVERT_HANDLER::GIT_REVERT_HANDLER( git_repository* aRepository )
|
||||
{
|
||||
m_repository = aRepository;
|
||||
}
|
||||
|
||||
GIT_REVERT_HANDLER::~GIT_REVERT_HANDLER()
|
||||
{
|
||||
}
|
||||
|
||||
bool GIT_REVERT_HANDLER::Revert( const wxString& aFilePath )
|
||||
{
|
||||
m_filesToRevert.push_back( aFilePath );
|
||||
return true;
|
||||
}
|
||||
|
||||
static void checkout_progress_cb(const char *path, size_t cur, size_t tot, void *payload)
|
||||
{
|
||||
wxLogDebug( "checkout_progress_cb: %s %zu/%zu", path, cur, tot );
|
||||
}
|
||||
|
||||
|
||||
static int checkout_notify_cb(git_checkout_notify_t why, const char *path,
|
||||
const git_diff_file *baseline,
|
||||
const git_diff_file *target,
|
||||
const git_diff_file *workdir, void *payload)
|
||||
{
|
||||
GIT_REVERT_HANDLER* handler = static_cast<GIT_REVERT_HANDLER*>(payload);
|
||||
|
||||
if( why & ( GIT_CHECKOUT_NOTIFY_CONFLICT | GIT_CHECKOUT_NOTIFY_IGNORED | GIT_CHECKOUT_NOTIFY_UPDATED ) )
|
||||
handler->PushFailedFile( path );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GIT_REVERT_HANDLER::PerformRevert()
|
||||
{
|
||||
git_object* head_commit = NULL;
|
||||
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||
|
||||
// Get the HEAD commit
|
||||
if (git_revparse_single(&head_commit, m_repository, "HEAD") != 0) {
|
||||
// Handle error. If we cannot get the HEAD, then there's no point proceeding.
|
||||
return;
|
||||
}
|
||||
|
||||
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
char** paths = new char*[m_filesToRevert.size()];
|
||||
|
||||
for( size_t ii = 0; ii < m_filesToRevert.size(); ii++ )
|
||||
{
|
||||
// Set paths to the specific file
|
||||
paths[ii] = wxStrdup( m_filesToRevert[ii].ToUTF8() );
|
||||
}
|
||||
|
||||
git_strarray arr = { paths, m_filesToRevert.size() };
|
||||
|
||||
opts.paths = arr;
|
||||
opts.progress_cb = checkout_progress_cb;
|
||||
opts.notify_cb = checkout_notify_cb;
|
||||
opts.notify_payload = static_cast<void*>(this);
|
||||
|
||||
// Attempt to checkout the file(s)
|
||||
if (git_checkout_tree(m_repository, head_commit, &opts) != 0)
|
||||
{
|
||||
const git_error *e = git_error_last();
|
||||
if (e)
|
||||
{
|
||||
wxLogError( "Checkout failed: %d: %s", e->klass, e->message );
|
||||
}
|
||||
}
|
||||
|
||||
// Free the HEAD commit
|
||||
for( size_t ii = 0; ii < m_filesToRevert.size(); ii++ )
|
||||
delete( paths[ii] );
|
||||
|
||||
delete[] paths;
|
||||
|
||||
git_object_free(head_commit);
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_REVERT_HANDLER_H_
|
||||
#define GIT_REVERT_HANDLER_H_
|
||||
|
||||
#include <git2.h>
|
||||
#include <vector>
|
||||
|
||||
class wxString;
|
||||
|
||||
class GIT_REVERT_HANDLER
|
||||
{
|
||||
public:
|
||||
GIT_REVERT_HANDLER( git_repository* aRepository );
|
||||
virtual ~GIT_REVERT_HANDLER();
|
||||
|
||||
bool Revert( const wxString& aFilePath );
|
||||
|
||||
void PerformRevert();
|
||||
|
||||
void PushFailedFile( const wxString& aFilePath )
|
||||
{
|
||||
m_filesFailedToRevert.push_back( aFilePath );
|
||||
}
|
||||
|
||||
private:
|
||||
git_repository* m_repository;
|
||||
|
||||
std::vector<wxString> m_filesToRevert;
|
||||
std::vector<wxString> m_filesFailedToRevert;
|
||||
};
|
||||
|
||||
#endif /* GIT_REVERT_HANDLER_H_ */
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_sync_handler.h"
|
||||
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <git2.h>
|
||||
|
||||
GIT_SYNC_HANDLER::GIT_SYNC_HANDLER( git_repository* aRepository )
|
||||
{
|
||||
m_repository = aRepository;
|
||||
}
|
||||
|
||||
|
||||
GIT_SYNC_HANDLER::~GIT_SYNC_HANDLER()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool GIT_SYNC_HANDLER::PerformSync()
|
||||
{
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_SYNC_HANDLER_H_
|
||||
#define GIT_SYNC_HANDLER_H_
|
||||
|
||||
#include <git2.h>
|
||||
|
||||
class wxString;
|
||||
|
||||
class GIT_SYNC_HANDLER
|
||||
{
|
||||
public:
|
||||
GIT_SYNC_HANDLER( git_repository* aRepository );
|
||||
virtual ~GIT_SYNC_HANDLER();
|
||||
|
||||
bool PerformSync();
|
||||
|
||||
private:
|
||||
git_repository* m_repository;
|
||||
};
|
||||
|
||||
#endif /* GIT_SYNC_HANDLER_H_ */
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <streambuf>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <git2.h>
|
||||
|
||||
#include <richio.h>
|
||||
|
||||
|
||||
class BLOB_BUFFER_STREAM : public std::streambuf
|
||||
{
|
||||
public:
|
||||
BLOB_BUFFER_STREAM( git_blob* aBlob )
|
||||
{
|
||||
// Yay C++
|
||||
setg( const_cast<char*>( static_cast<const char*>( git_blob_rawcontent( aBlob ) ) ),
|
||||
const_cast<char*>( static_cast<const char*>( git_blob_rawcontent( aBlob ) ) ),
|
||||
const_cast<char*>( static_cast<const char*>( git_blob_rawcontent( aBlob ) ) ) + git_blob_rawsize( aBlob ) );
|
||||
}
|
||||
|
||||
~BLOB_BUFFER_STREAM() override
|
||||
{
|
||||
}
|
||||
|
||||
int overflow( int c ) override
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
std::streamsize xsputn( const char* s, std::streamsize n ) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Build a class that implements LINE_READER for git_blobs
|
||||
class BLOB_READER : public LINE_READER
|
||||
{
|
||||
public:
|
||||
BLOB_READER( git_blob* aBlob ) : m_blob( aBlob )
|
||||
{
|
||||
m_stream = new BLOB_BUFFER_STREAM( m_blob );
|
||||
m_istream = new std::istream( m_stream );
|
||||
m_line = nullptr;
|
||||
m_lineNum = 0;
|
||||
}
|
||||
|
||||
~BLOB_READER() override
|
||||
{
|
||||
delete m_istream;
|
||||
delete m_stream;
|
||||
}
|
||||
|
||||
char* ReadLine() override
|
||||
{
|
||||
getline( *m_istream, m_buffer );
|
||||
|
||||
m_buffer.append( 1, '\n' );
|
||||
|
||||
m_length = m_buffer.size();
|
||||
m_line = (char*) m_buffer.data(); //ew why no const??
|
||||
|
||||
// lineNum is incremented even if there was no line read, because this
|
||||
// leads to better error reporting when we hit an end of file.
|
||||
++m_lineNum;
|
||||
|
||||
return m_istream->eof() ? nullptr : m_line;
|
||||
}
|
||||
|
||||
private:
|
||||
git_blob* m_blob;
|
||||
BLOB_BUFFER_STREAM* m_stream;
|
||||
std::istream* m_istream;
|
||||
std::string m_buffer;
|
||||
};
|
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "kicad_git_common.h"
|
||||
|
||||
#include <wx/filename.h>
|
||||
#include <wx/log.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
KIGIT_COMMON::KIGIT_COMMON( git_repository* aRepo ) : m_repo( aRepo )
|
||||
{}
|
||||
|
||||
KIGIT_COMMON::~KIGIT_COMMON()
|
||||
{}
|
||||
|
||||
git_repository* KIGIT_COMMON::GetRepo() const
|
||||
{
|
||||
return m_repo;
|
||||
}
|
||||
|
||||
wxString KIGIT_COMMON::GetCurrentBranchName() const
|
||||
{
|
||||
git_reference* head = nullptr;
|
||||
|
||||
int retval = git_repository_head( &head, m_repo );
|
||||
|
||||
if( retval && retval != GIT_EUNBORNBRANCH && retval != GIT_ENOTFOUND )
|
||||
return wxEmptyString;
|
||||
|
||||
git_reference *branch;
|
||||
|
||||
if( git_reference_resolve( &branch, head ) )
|
||||
{
|
||||
git_reference_free( head );
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
git_reference_free( head );
|
||||
const char* branchName = "";
|
||||
|
||||
if( git_branch_name( &branchName, branch ) )
|
||||
{
|
||||
git_reference_free( branch );
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
git_reference_free( branch );
|
||||
|
||||
return branchName;
|
||||
}
|
||||
|
||||
|
||||
std::vector<wxString> KIGIT_COMMON::GetBranchNames() const
|
||||
{
|
||||
std::vector<wxString> branchNames;
|
||||
std::map<git_time_t, wxString> branchNamesMap;
|
||||
wxString firstName;
|
||||
|
||||
git_branch_iterator* branchIterator = nullptr;
|
||||
|
||||
if( git_branch_iterator_new( &branchIterator, m_repo, GIT_BRANCH_LOCAL ) )
|
||||
return branchNames;
|
||||
|
||||
git_reference* branchReference = nullptr;
|
||||
git_branch_t branchType;
|
||||
|
||||
while( git_branch_next( &branchReference, &branchType, branchIterator ) != GIT_ITEROVER )
|
||||
{
|
||||
const char* branchName = "";
|
||||
|
||||
if( git_branch_name( &branchName, branchReference ) )
|
||||
continue;
|
||||
|
||||
const git_oid* commitId = git_reference_target( branchReference );
|
||||
|
||||
git_commit* commit = nullptr;
|
||||
|
||||
if( git_commit_lookup( &commit, m_repo, commitId ) )
|
||||
continue;
|
||||
|
||||
git_time_t commitTime = git_commit_time( commit );
|
||||
|
||||
if( git_branch_is_head( branchReference ) )
|
||||
firstName = branchName;
|
||||
else
|
||||
branchNamesMap.emplace( commitTime, branchName );
|
||||
|
||||
git_commit_free( commit );
|
||||
git_reference_free( branchReference );
|
||||
}
|
||||
|
||||
git_branch_iterator_free( branchIterator );
|
||||
|
||||
// Add the current branch to the top of the list
|
||||
if( !firstName.IsEmpty() )
|
||||
branchNames.push_back( firstName );
|
||||
|
||||
// Add the remaining branches in order from newest to oldest
|
||||
for( auto rit = branchNamesMap.rbegin(); rit != branchNamesMap.rend(); ++rit )
|
||||
branchNames.push_back( rit->second );
|
||||
|
||||
return branchNames;
|
||||
}
|
||||
|
||||
|
||||
std::vector<wxString> KIGIT_COMMON::GetProjectDirs()
|
||||
{
|
||||
std::vector<wxString> projDirs;
|
||||
|
||||
git_oid oid;
|
||||
git_commit* commit;
|
||||
git_tree *tree;
|
||||
|
||||
if( git_reference_name_to_id( &oid, m_repo, "HEAD" ) != GIT_OK )
|
||||
{
|
||||
wxLogError( "An error occurred: %s", git_error_last()->message );
|
||||
return projDirs;
|
||||
}
|
||||
|
||||
if( git_commit_lookup( &commit, m_repo, &oid ) != GIT_OK )
|
||||
{
|
||||
wxLogError( "An error occurred: %s", git_error_last()->message );
|
||||
return projDirs;
|
||||
}
|
||||
|
||||
if( git_commit_tree( &tree, commit ) != GIT_OK )
|
||||
{
|
||||
wxLogError( "An error occurred: %s", git_error_last()->message );
|
||||
return projDirs;
|
||||
}
|
||||
|
||||
// Define callback
|
||||
git_tree_walk(
|
||||
tree, GIT_TREEWALK_PRE,
|
||||
[]( const char* root, const git_tree_entry* entry, void* payload )
|
||||
{
|
||||
std::vector<wxString>* prjs = static_cast<std::vector<wxString>*>( payload );
|
||||
wxFileName root_fn( git_tree_entry_name( entry ) );
|
||||
|
||||
root_fn.SetPath( root );
|
||||
|
||||
if( git_tree_entry_type( entry ) == GIT_OBJECT_BLOB
|
||||
&& ( ( root_fn.GetExt() == "kicad_pro" ) || ( root_fn.GetExt() == "pro" ) ) )
|
||||
{
|
||||
prjs->push_back( root_fn.GetFullPath() );
|
||||
}
|
||||
|
||||
return 0; // continue walking
|
||||
},
|
||||
&projDirs );
|
||||
|
||||
git_tree_free( tree );
|
||||
git_commit_free( commit );
|
||||
|
||||
std::sort( projDirs.begin(), projDirs.end(),
|
||||
[]( const wxString& a, const wxString& b )
|
||||
{
|
||||
int a_freq = a.Freq( wxFileName::GetPathSeparator() );
|
||||
int b_freq = b.Freq( wxFileName::GetPathSeparator() );
|
||||
|
||||
if( a_freq == b_freq )
|
||||
return a < b;
|
||||
else
|
||||
return a_freq < b_freq;
|
||||
|
||||
} );
|
||||
|
||||
return projDirs;
|
||||
}
|
||||
|
||||
|
||||
std::pair<std::set<wxString>,std::set<wxString>> KIGIT_COMMON::GetDifferentFiles() const
|
||||
{
|
||||
auto get_modified_files = [&]( git_oid* from_oid, git_oid* to_oid ) -> std::set<wxString>
|
||||
{
|
||||
std::set<wxString> modified_set;
|
||||
git_revwalk* walker = nullptr;
|
||||
|
||||
if( git_revwalk_new( &walker, m_repo ) != GIT_OK )
|
||||
return modified_set;
|
||||
|
||||
if( ( git_revwalk_push( walker, from_oid ) != GIT_OK )
|
||||
|| ( git_revwalk_hide( walker, to_oid ) != GIT_OK ) )
|
||||
{
|
||||
git_revwalk_free( walker );
|
||||
return modified_set;
|
||||
}
|
||||
|
||||
git_oid oid;
|
||||
git_commit* commit;
|
||||
|
||||
// iterate over all local commits not in remote
|
||||
while( git_revwalk_next( &oid, walker ) == GIT_OK )
|
||||
{
|
||||
if( git_commit_lookup( &commit, m_repo, &oid ) != GIT_OK )
|
||||
continue;
|
||||
|
||||
git_tree *tree, *parent_tree = nullptr;
|
||||
if( git_commit_tree( &tree, commit ) != GIT_OK )
|
||||
{
|
||||
git_commit_free( commit );
|
||||
continue;
|
||||
}
|
||||
|
||||
// get parent commit tree to diff against
|
||||
if( !git_commit_parentcount( commit ) )
|
||||
{
|
||||
git_tree_free( tree );
|
||||
git_commit_free( commit );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
git_commit* parent;
|
||||
if( git_commit_parent( &parent, commit, 0 ) != GIT_OK )
|
||||
{
|
||||
git_tree_free( tree );
|
||||
git_commit_free( commit );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if( git_commit_tree( &parent_tree, parent ) != GIT_OK )
|
||||
{
|
||||
git_tree_free( tree );
|
||||
git_commit_free( commit );
|
||||
git_commit_free( parent );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
git_diff* diff;
|
||||
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
|
||||
|
||||
if( git_diff_tree_to_tree( &diff, m_repo, parent_tree, tree, &diff_opts ) == GIT_OK )
|
||||
{
|
||||
size_t num_deltas = git_diff_num_deltas( diff );
|
||||
|
||||
for( size_t i = 0; i < num_deltas; ++i )
|
||||
{
|
||||
const git_diff_delta* delta = git_diff_get_delta( diff, i );
|
||||
modified_set.insert( delta->new_file.path );
|
||||
}
|
||||
|
||||
git_diff_free( diff );
|
||||
}
|
||||
|
||||
git_tree_free( parent_tree );
|
||||
git_commit_free( parent );
|
||||
git_tree_free( tree );
|
||||
git_commit_free( commit );
|
||||
}
|
||||
|
||||
git_revwalk_free( walker );
|
||||
|
||||
return modified_set;
|
||||
};
|
||||
|
||||
std::pair<std::set<wxString>,std::set<wxString>> modified_files;
|
||||
|
||||
if( !m_repo )
|
||||
return modified_files;
|
||||
|
||||
git_reference* head = nullptr;
|
||||
git_reference* remote_head = nullptr;
|
||||
|
||||
if( git_repository_head( &head, m_repo ) != GIT_OK )
|
||||
return modified_files;
|
||||
|
||||
if( git_branch_upstream( &remote_head, head ) != GIT_OK )
|
||||
{
|
||||
git_reference_free( head );
|
||||
return modified_files;
|
||||
}
|
||||
|
||||
git_oid head_oid = *git_reference_target( head );
|
||||
git_oid remote_oid = *git_reference_target( remote_head );
|
||||
|
||||
git_reference_free( head );
|
||||
git_reference_free( remote_head );
|
||||
|
||||
modified_files.first = get_modified_files( &head_oid, &remote_oid );
|
||||
modified_files.second = get_modified_files( &remote_oid, &head_oid );
|
||||
|
||||
return modified_files;
|
||||
}
|
||||
|
||||
|
||||
bool KIGIT_COMMON::HasLocalCommits() const
|
||||
{
|
||||
if( !m_repo )
|
||||
return false;
|
||||
|
||||
git_reference* head = nullptr;
|
||||
git_reference* remote_head = nullptr;
|
||||
|
||||
if( git_repository_head( &head, m_repo ) != GIT_OK )
|
||||
return false;
|
||||
|
||||
if( git_branch_upstream( &remote_head, head ) != GIT_OK )
|
||||
{
|
||||
git_reference_free( head );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_oid head_oid = *git_reference_target( head );
|
||||
git_oid remote_oid = *git_reference_target( remote_head );
|
||||
|
||||
git_reference_free( head );
|
||||
git_reference_free( remote_head );
|
||||
|
||||
git_revwalk* walker = nullptr;
|
||||
|
||||
if( git_revwalk_new( &walker, m_repo ) != GIT_OK )
|
||||
return false;
|
||||
|
||||
if( ( git_revwalk_push( walker, &head_oid ) != GIT_OK )
|
||||
|| ( git_revwalk_hide( walker, &remote_oid ) != GIT_OK ) )
|
||||
{
|
||||
git_revwalk_free( walker );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_oid oid;
|
||||
|
||||
// If we can't walk to the next commit, then we are at or behind the remote
|
||||
if( git_revwalk_next( &oid, walker ) != GIT_OK )
|
||||
{
|
||||
git_revwalk_free( walker );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_revwalk_free( walker );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool KIGIT_COMMON::HasPushAndPullRemote() const
|
||||
{
|
||||
git_remote* remote = nullptr;
|
||||
|
||||
if( git_remote_lookup( &remote, m_repo, "origin" ) != GIT_OK )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the URLs associated with the remote
|
||||
const char* fetch_url = git_remote_url( remote );
|
||||
const char* push_url = git_remote_pushurl( remote );
|
||||
|
||||
// If no push URL is set, libgit2 defaults to using the fetch URL for pushing
|
||||
if( !push_url )
|
||||
{
|
||||
push_url = fetch_url;
|
||||
}
|
||||
|
||||
// Clean up the remote object
|
||||
git_remote_free( remote );
|
||||
|
||||
// Check if both URLs are valid (i.e., not NULL)
|
||||
return fetch_url && push_url;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int fetchhead_foreach_cb( const char*, const char*,
|
||||
const git_oid* aOID, unsigned int aIsMerge, void* aPayload )
|
||||
{
|
||||
if( aIsMerge )
|
||||
git_oid_cpy( (git_oid*) aPayload, aOID );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void clone_progress_cb( const char* aStr, size_t aLen, size_t aTotal, void* data )
|
||||
{
|
||||
KIGIT_COMMON* parent = (KIGIT_COMMON*) data;
|
||||
|
||||
wxString progressMessage( aStr );
|
||||
parent->UpdateProgress( aLen, aTotal, progressMessage );
|
||||
}
|
||||
|
||||
|
||||
extern "C" int progress_cb( const char* str, int len, void* data )
|
||||
{
|
||||
KIGIT_COMMON* parent = (KIGIT_COMMON*) data;
|
||||
|
||||
wxString progressMessage( str, len );
|
||||
parent->UpdateProgress( 0, 0, progressMessage );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int transfer_progress_cb( const git_transfer_progress* aStats, void* aPayload )
|
||||
{
|
||||
KIGIT_COMMON* parent = (KIGIT_COMMON*) aPayload;
|
||||
wxString progressMessage = wxString::Format( _( "Received %u of %u objects" ),
|
||||
aStats->received_objects, aStats->total_objects );
|
||||
|
||||
parent->UpdateProgress( aStats->received_objects, aStats->total_objects, progressMessage );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int update_cb( const char* aRefname, const git_oid* aFirst, const git_oid* aSecond,
|
||||
void* aPayload )
|
||||
{
|
||||
constexpr int cstring_len = 8;
|
||||
char a_str[cstring_len + 1];
|
||||
char b_str[cstring_len + 1];
|
||||
|
||||
KIGIT_COMMON* parent = (KIGIT_COMMON*) aPayload;
|
||||
wxString status;
|
||||
|
||||
git_oid_tostr( b_str, cstring_len, aSecond );
|
||||
|
||||
if( !git_oid_is_zero( aFirst ) )
|
||||
{
|
||||
git_oid_tostr( a_str, cstring_len, aFirst );
|
||||
status = wxString::Format( _( "* [updated] %s..%s %s" ), a_str, b_str, aRefname );
|
||||
}
|
||||
else
|
||||
{
|
||||
status = wxString::Format( _( "* [new] %s %s" ), b_str, aRefname );
|
||||
}
|
||||
|
||||
parent->UpdateProgress( 0, 0, status );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int push_transfer_progress_cb( unsigned int aCurrent, unsigned int aTotal, size_t aBytes,
|
||||
void* aPayload )
|
||||
{
|
||||
int64_t progress = 100;
|
||||
KIGIT_COMMON* parent = (KIGIT_COMMON*) aPayload;
|
||||
|
||||
if( aTotal != 0 )
|
||||
{
|
||||
progress = ( aCurrent * 100 ) / aTotal;
|
||||
}
|
||||
|
||||
wxString progressMessage = wxString::Format( _( "Writing objects: %d%% (%d/%d), %d bytes" ),
|
||||
progress, aCurrent, aTotal, aBytes );
|
||||
parent->UpdateProgress( aCurrent, aTotal, progressMessage );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int push_update_reference_cb( const char* aRefname, const char* aStatus, void* aPayload )
|
||||
{
|
||||
KIGIT_COMMON* parent = (KIGIT_COMMON*) aPayload;
|
||||
wxString status( aStatus );
|
||||
|
||||
if( !status.IsEmpty() )
|
||||
{
|
||||
wxString statusMessage = wxString::Format( _( "* [rejected] %s (%s)" ), aRefname, aStatus );
|
||||
parent->UpdateProgress( 0, 0, statusMessage );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString statusMessage = wxString::Format( _( "[updated] %s" ), aRefname );
|
||||
parent->UpdateProgress( 0, 0, statusMessage );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int credentials_cb( git_cred** aOut, const char* aUrl, const char* aUsername,
|
||||
unsigned int aAllowedTypes, void* aPayload )
|
||||
{
|
||||
KIGIT_COMMON* parent = static_cast<KIGIT_COMMON*>( aPayload );
|
||||
|
||||
if( parent->GetConnType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_LOCAL )
|
||||
return GIT_PASSTHROUGH;
|
||||
|
||||
if( aAllowedTypes & GIT_CREDENTIAL_USERNAME
|
||||
&& !( parent->TestedTypes() & GIT_CREDTYPE_USERNAME ) )
|
||||
{
|
||||
wxString username = parent->GetUsername().Trim().Trim( false );
|
||||
git_cred_username_new( aOut, username.ToStdString().c_str() );
|
||||
parent->TestedTypes() |= GIT_CREDTYPE_USERNAME;
|
||||
}
|
||||
else if( parent->GetConnType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS
|
||||
&& ( aAllowedTypes & GIT_CREDENTIAL_USERPASS_PLAINTEXT )
|
||||
&& !( parent->TestedTypes() & GIT_CREDTYPE_USERPASS_PLAINTEXT ) )
|
||||
{
|
||||
wxString username = parent->GetUsername().Trim().Trim( false );
|
||||
wxString password = parent->GetPassword().Trim().Trim( false );
|
||||
|
||||
git_cred_userpass_plaintext_new( aOut, username.ToStdString().c_str(),
|
||||
password.ToStdString().c_str() );
|
||||
parent->TestedTypes() |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
|
||||
}
|
||||
else if( parent->GetConnType() == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH
|
||||
&& ( aAllowedTypes & GIT_CREDENTIAL_SSH_KEY )
|
||||
&& !( parent->TestedTypes() & GIT_CREDTYPE_SSH_KEY ) )
|
||||
{
|
||||
// SSH key authentication
|
||||
wxString sshKey = parent->GetSSHKey();
|
||||
wxString sshPubKey = sshKey + ".pub";
|
||||
wxString username = parent->GetUsername().Trim().Trim( false );
|
||||
wxString password = parent->GetPassword().Trim().Trim( false );
|
||||
|
||||
git_cred_ssh_key_new( aOut, username.ToStdString().c_str(),
|
||||
sshPubKey.ToStdString().c_str(),
|
||||
sshKey.ToStdString().c_str(),
|
||||
password.ToStdString().c_str() );
|
||||
parent->TestedTypes() |= GIT_CREDTYPE_SSH_KEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GIT_PASSTHROUGH;
|
||||
}
|
||||
|
||||
return GIT_OK;
|
||||
};
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef _GIT_COMMON_H_
|
||||
#define _GIT_COMMON_H_
|
||||
|
||||
#include <git/kicad_git_errors.h>
|
||||
|
||||
#include <git2.h>
|
||||
#include <set>
|
||||
|
||||
#include <wx/string.h>
|
||||
|
||||
class KIGIT_COMMON : public KIGIT_ERRORS
|
||||
{
|
||||
|
||||
public:
|
||||
KIGIT_COMMON( git_repository* aRepo );
|
||||
~KIGIT_COMMON();
|
||||
|
||||
git_repository* GetRepo() const;
|
||||
|
||||
void SetRepo( git_repository* aRepo )
|
||||
{
|
||||
m_repo = aRepo;
|
||||
}
|
||||
|
||||
wxString GetCurrentBranchName() const;
|
||||
|
||||
std::vector<wxString> GetBranchNames() const;
|
||||
|
||||
virtual void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) {};
|
||||
|
||||
/**
|
||||
* Return a vector of project files in the repository. Sorted by the depth of
|
||||
* the project file in the directory tree
|
||||
*
|
||||
* @return std::vector<wxString> of project files
|
||||
*/
|
||||
std::vector<wxString> GetProjectDirs();
|
||||
|
||||
/**
|
||||
* Return a pair of sets of files that differ locally from the remote repository
|
||||
* The first set is files that have been committed locally but not pushed
|
||||
* The second set is files that have been committed remotely but not pulled
|
||||
*/
|
||||
std::pair<std::set<wxString>,std::set<wxString>> GetDifferentFiles() const;
|
||||
|
||||
enum class GIT_STATUS
|
||||
{
|
||||
GIT_STATUS_UNTRACKED,
|
||||
GIT_STATUS_CURRENT,
|
||||
GIT_STATUS_MODIFIED, // File changed but not committed to local repository
|
||||
GIT_STATUS_ADDED,
|
||||
GIT_STATUS_DELETED,
|
||||
GIT_STATUS_BEHIND, // File changed in remote repository but not in local
|
||||
GIT_STATUS_AHEAD, // File changed in local repository but not in remote
|
||||
GIT_STATUS_CONFLICTED,
|
||||
GIT_STATUS_LAST
|
||||
};
|
||||
|
||||
enum class GIT_CONN_TYPE
|
||||
{
|
||||
GIT_CONN_HTTPS = 0,
|
||||
GIT_CONN_SSH,
|
||||
GIT_CONN_LOCAL,
|
||||
GIT_CONN_LAST
|
||||
};
|
||||
|
||||
wxString GetUsername() const { return m_username; }
|
||||
wxString GetPassword() const { return m_password; }
|
||||
wxString GetSSHKey() const { return m_sshKey; }
|
||||
GIT_CONN_TYPE GetConnType() const { return m_connType; }
|
||||
|
||||
void SetUsername( const wxString& aUsername ) { m_username = aUsername; }
|
||||
void SetPassword( const wxString& aPassword ) { m_password = aPassword; }
|
||||
void SetSSHKey( const wxString& aSSHKey ) { m_sshKey = aSSHKey; }
|
||||
|
||||
void SetConnType( GIT_CONN_TYPE aConnType ) { m_connType = aConnType; }
|
||||
void SetConnType( unsigned aConnType )
|
||||
{
|
||||
if( aConnType < static_cast<unsigned>( GIT_CONN_TYPE::GIT_CONN_LAST ) )
|
||||
m_connType = static_cast<GIT_CONN_TYPE>( aConnType );
|
||||
}
|
||||
|
||||
// Holds a temporary variable that can be used by the authentication callback
|
||||
// to remember which types of authentication have been tested so that we
|
||||
// don't loop forever.
|
||||
unsigned& TestedTypes() { return m_testedTypes; }
|
||||
|
||||
// Returns true if the repository has local commits that have not been pushed
|
||||
bool HasLocalCommits() const;
|
||||
|
||||
// Returns true if the repository has a remote that can be pushed to pulled from
|
||||
bool HasPushAndPullRemote() const;
|
||||
|
||||
protected:
|
||||
git_repository* m_repo;
|
||||
|
||||
GIT_CONN_TYPE m_connType;
|
||||
wxString m_username;
|
||||
wxString m_password;
|
||||
wxString m_sshKey;
|
||||
|
||||
unsigned m_testedTypes;
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern "C" int progress_cb( const char* str, int len, void* data );
|
||||
extern "C" void clone_progress_cb( const char* str, size_t len, size_t total, void* data );
|
||||
extern "C" int transfer_progress_cb( const git_transfer_progress* aStats, void* aPayload );
|
||||
extern "C" int update_cb( const char* aRefname, const git_oid* aFirst, const git_oid* aSecond,
|
||||
void* aPayload );
|
||||
extern "C" int push_transfer_progress_cb( unsigned int aCurrent, unsigned int aTotal,
|
||||
size_t aBytes, void* aPayload );
|
||||
extern "C" int push_update_reference_cb( const char* aRefname, const char* aStatus,
|
||||
void* aPayload );
|
||||
|
||||
extern "C" int fetchhead_foreach_cb( const char*, const char*,
|
||||
const git_oid* aOID, unsigned int aIsMerge, void* aPayload );
|
||||
extern "C" int credentials_cb( git_cred** aOut, const char* aUrl, const char* aUsername,
|
||||
unsigned int aAllowedTypes, void* aPayload );
|
||||
|
||||
#endif // _GIT_COMMON_H_
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
namespace KIGIT_ERROR
|
||||
{
|
||||
#undef _
|
||||
#define _(a) a
|
||||
|
||||
// General errors
|
||||
const char* const kInvalidRepository = _("Invalid repository.");
|
||||
const char* const kCommitFailed = _("Failed to commit changes.");
|
||||
const char* const kMergeFailed = _("Failed to merge branches.");
|
||||
|
||||
// Clone errors
|
||||
const char* const kCloneFailed = _("Failed to clone repository.");
|
||||
const char* const kRemoteNotFound = _("Remote repository not found.");
|
||||
const char* const kAuthenticationFailed = _("Authentication failed for remote repository.");
|
||||
|
||||
// Branch errors
|
||||
const char* const kBranchNotFound = _("Branch not found.");
|
||||
const char* const kBranchCreationFailed = _("Failed to create branch.");
|
||||
const char* const kBranchDeletionFailed = _("Failed to delete branch.");
|
||||
|
||||
// Checkout errors
|
||||
const char* const kCheckoutFailed = _("Failed to perform checkout operation.");
|
||||
const char* const kFileNotFoundInCheckout = _("File not found during checkout operation.");
|
||||
|
||||
// Conflict errors
|
||||
const char* const kMergeConflict = _("Merge conflict encountered.");
|
||||
const char* const kRebaseConflict = _("Rebase conflict encountered.");
|
||||
|
||||
// Pull/Push errors
|
||||
const char* const kPullFailed = _("Failed to pull changes from remote repository.");
|
||||
const char* const kPushFailed = _("Failed to push changes to remote repository.");
|
||||
const char* const kNoUpstreamBranch = _("No upstream branch configured.");
|
||||
const char* const kRemoteConnectionError = _("Failed to establish connection with remote repository.");
|
||||
|
||||
// Tag errors
|
||||
const char* const kTagNotFound = _("Tag not found.");
|
||||
const char* const kTagCreationFailed = _("Failed to create tag.");
|
||||
const char* const kTagDeletionFailed = _("Failed to delete tag.");
|
||||
|
||||
const char* const kUnknownError = _("Unknown error.");
|
||||
const char* const kNoError = _("No error.");
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* 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 3
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef KICAD_GIT_ERRORS_H
|
||||
#define KICAD_GIT_ERRORS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <wx/translation.h>
|
||||
|
||||
class KIGIT_ERRORS
|
||||
{
|
||||
public:
|
||||
|
||||
KIGIT_ERRORS() = default;
|
||||
|
||||
const std::vector<wxString>& GetErrorStrings() const
|
||||
{
|
||||
return m_errorStrings;
|
||||
}
|
||||
|
||||
const wxString& PeekErrorString() const
|
||||
{
|
||||
if( m_errorStrings.empty() )
|
||||
return _( "No error" );
|
||||
else
|
||||
return m_errorStrings.back();
|
||||
}
|
||||
|
||||
wxString GetErrorString()
|
||||
{
|
||||
if( m_errorStrings.empty() )
|
||||
return _( "No error" );
|
||||
|
||||
const wxString errorString( m_errorStrings.back() );
|
||||
m_errorStrings.pop_back();
|
||||
return errorString;
|
||||
}
|
||||
|
||||
void AddErrorString( const wxString aErrorString )
|
||||
{
|
||||
m_errorStrings.emplace_back( aErrorString );
|
||||
}
|
||||
|
||||
void AddErrorString( const std::string aErrorString )
|
||||
{
|
||||
m_errorStrings.emplace_back( aErrorString );
|
||||
}
|
||||
|
||||
void ClearErrorStrings()
|
||||
{
|
||||
m_errorStrings.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<wxString> m_errorStrings;
|
||||
|
||||
};
|
||||
|
||||
#endif // KICAD_GIT_ERRORS_H
|
|
@ -177,6 +177,18 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
|
|||
ZONE_DISPLAY_MODE::SHOW_FILLED, ZONE_DISPLAY_MODE::SHOW_FILLED,
|
||||
ZONE_DISPLAY_MODE::SHOW_TRIANGULATION ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "git.repo_username",
|
||||
&m_GitRepoUsername, "" ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "git.repo_password",
|
||||
&m_GitRepoPassword, "" ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "git.repo_type",
|
||||
&m_GitRepoType, "" ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "git.ssh_key",
|
||||
&m_GitSSHKey, "" ) );
|
||||
|
||||
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "project.files",
|
||||
[&]() -> nlohmann::json
|
||||
{
|
||||
|
|
|
@ -347,6 +347,61 @@ COMMON_SETTINGS::COMMON_SETTINGS() :
|
|||
m_params.emplace_back( new PARAM<int>( "package_manager.sash_pos",
|
||||
&m_PackageManager.sash_pos, 380 ) );
|
||||
|
||||
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "git.repositories",
|
||||
[&]() -> nlohmann::json
|
||||
{
|
||||
nlohmann::json ret = {};
|
||||
|
||||
for( const GIT_REPOSITORY& repo : m_Git.repositories )
|
||||
{
|
||||
nlohmann::json repoJson = {};
|
||||
|
||||
repoJson["name"] = repo.name;
|
||||
repoJson["path"] = repo.path;
|
||||
repoJson["authType"] = repo.authType;
|
||||
repoJson["username"] = repo.username;
|
||||
repoJson["ssh_path"] = repo.ssh_path;
|
||||
repoJson["active"] = repo.active;
|
||||
|
||||
ret.push_back( repoJson );
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
[&]( const nlohmann::json& aJson )
|
||||
{
|
||||
if( !aJson.is_array() )
|
||||
return;
|
||||
|
||||
m_Git.repositories.clear();
|
||||
|
||||
for( const auto& repoJson : aJson )
|
||||
{
|
||||
GIT_REPOSITORY repo;
|
||||
|
||||
repo.name = repoJson["name"].get<wxString>();
|
||||
repo.path = repoJson["path"].get<wxString>();
|
||||
repo.authType = repoJson["authType"].get<wxString>();
|
||||
repo.username = repoJson["username"].get<wxString>();
|
||||
repo.ssh_path = repoJson["ssh_path"].get<wxString>();
|
||||
repo.active = repoJson["active"].get<bool>();
|
||||
|
||||
m_Git.repositories.push_back( repo );
|
||||
}
|
||||
},
|
||||
{} ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "git.authorName",
|
||||
&m_Git.authorName, wxS( "" ) ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "git.authorEmail",
|
||||
&m_Git.authorEmail, wxS( "" ) ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "git.useDefaultAuthor",
|
||||
&m_Git.useDefaultAuthor, true ) );
|
||||
|
||||
|
||||
|
||||
registerMigration( 0, 1, std::bind( &COMMON_SETTINGS::migrateSchema0to1, this ) );
|
||||
registerMigration( 1, 2, std::bind( &COMMON_SETTINGS::migrateSchema1to2, this ) );
|
||||
registerMigration( 2, 3, std::bind( &COMMON_SETTINGS::migrateSchema2to3, this ) );
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
#include <kiplatform/app.h>
|
||||
#include <kiplatform/environment.h>
|
||||
|
||||
#include <git2.h>
|
||||
|
||||
#ifdef KICAD_USE_SENTRY
|
||||
#include <sentry.h>
|
||||
#endif
|
||||
|
@ -73,6 +75,7 @@ static struct PGM_SINGLE_TOP : public PGM_BASE
|
|||
|
||||
void OnPgmExit()
|
||||
{
|
||||
|
||||
Kiway.OnKiwayEnd();
|
||||
|
||||
if( m_settings_manager && m_settings_manager->IsOK() )
|
||||
|
@ -84,6 +87,7 @@ static struct PGM_SINGLE_TOP : public PGM_BASE
|
|||
// Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
|
||||
// earlier than wxApp and earlier than static destruction would.
|
||||
PGM_BASE::Destroy();
|
||||
git_libgit2_shutdown();
|
||||
}
|
||||
|
||||
void MacOpenFile( const wxString& aFileName ) override
|
||||
|
@ -298,6 +302,9 @@ bool PGM_SINGLE_TOP::OnPgmInit()
|
|||
}
|
||||
#endif
|
||||
|
||||
// Initialize the git library before trying to initialize individual programs
|
||||
git_libgit2_init();
|
||||
|
||||
// Not all kicad applications use the python stuff. skip python init
|
||||
// for these apps.
|
||||
bool skip_python_initialization = false;
|
||||
|
|
|
@ -589,6 +589,58 @@ bool LIB_FIELD::IsMandatory() const
|
|||
}
|
||||
|
||||
|
||||
bool LIB_FIELD::operator==( const LIB_ITEM& aItem ) const
|
||||
{
|
||||
if( aItem.Type() != LIB_FIELD_T )
|
||||
return false;
|
||||
|
||||
const LIB_FIELD& field = static_cast<const LIB_FIELD&>( aItem );
|
||||
|
||||
if( m_id != field.m_id )
|
||||
return false;
|
||||
|
||||
if( m_name != field.m_name )
|
||||
return false;
|
||||
|
||||
if( m_parent->m_Uuid != aItem.GetParent()->m_Uuid )
|
||||
return false;
|
||||
|
||||
if( m_id < MANDATORY_FIELDS )
|
||||
return true;
|
||||
|
||||
if( m_Uuid == field.m_Uuid )
|
||||
return true;
|
||||
|
||||
return EDA_TEXT::operator==( field );
|
||||
}
|
||||
|
||||
|
||||
double LIB_FIELD::Similarity( const LIB_ITEM& aItem ) const
|
||||
{
|
||||
if( aItem.Type() != LIB_FIELD_T )
|
||||
return 0.0;
|
||||
|
||||
const LIB_FIELD& field = static_cast<const LIB_FIELD&>( aItem );
|
||||
|
||||
if( m_id != field.m_id && m_id < MANDATORY_FIELDS )
|
||||
return 0.0;
|
||||
|
||||
if( m_parent->m_Uuid != aItem.GetParent()->m_Uuid )
|
||||
return 0.0;
|
||||
|
||||
if( m_id < MANDATORY_FIELDS )
|
||||
return 1.0;
|
||||
|
||||
if( m_Uuid == field.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
double similarity = SimilarityBase( field );
|
||||
|
||||
similarity *= EDA_TEXT::Similarity( field );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
static struct LIB_FIELD_DESC
|
||||
{
|
||||
LIB_FIELD_DESC()
|
||||
|
|
|
@ -198,6 +198,10 @@ public:
|
|||
bool ShowInChooser() const { return m_showInChooser; }
|
||||
void SetShowInChooser( bool aShow = true ) { m_showInChooser = aShow; }
|
||||
|
||||
double Similarity( const LIB_ITEM& aItem ) const override;
|
||||
|
||||
bool operator==( const LIB_ITEM& aItem ) const override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
|
@ -168,5 +168,3 @@ void LIB_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
|
|||
aLayers[1] = LAYER_DEVICE_BACKGROUND;
|
||||
aLayers[2] = LAYER_SELECTION_SHADOWS;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -204,6 +204,35 @@ public:
|
|||
return (LIB_SYMBOL*) m_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a measure of how likely the other object is to represent the same
|
||||
* object. The scale runs from 0.0 (definitely different objects) to 1.0 (same)
|
||||
*
|
||||
* This is a pure virtual function. Derived classes must implement this.
|
||||
*/
|
||||
virtual double Similarity( const LIB_ITEM& aItem ) const = 0;
|
||||
|
||||
/**
|
||||
* Calculate the boilerplate similarity for all LIB_ITEMs without
|
||||
* preventing the use above of a pure virtual function that catches at compile
|
||||
* time when a new object has not been fully implemented
|
||||
*/
|
||||
double SimilarityBase( const LIB_ITEM& aItem ) const
|
||||
{
|
||||
double similarity = 1.0;
|
||||
|
||||
if( m_unit != aItem.m_unit )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_convert != aItem.m_convert )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_private != aItem.m_private )
|
||||
similarity *= 0.9;
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
void ViewGetLayers( int aLayers[], int& aCount ) const override;
|
||||
|
||||
bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
|
||||
|
@ -237,7 +266,7 @@ public:
|
|||
* @param aOther Object to test against.
|
||||
* @return True if object is identical to this object.
|
||||
*/
|
||||
bool operator==( const LIB_ITEM& aOther ) const;
|
||||
virtual bool operator==( const LIB_ITEM& aOther ) const;
|
||||
bool operator==( const LIB_ITEM* aOther ) const
|
||||
{
|
||||
return *this == *aOther;
|
||||
|
|
|
@ -1453,6 +1453,123 @@ wxString LIB_PIN::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
|
|||
}
|
||||
|
||||
|
||||
bool LIB_PIN::operator==( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != LIB_PIN_T )
|
||||
return false;
|
||||
|
||||
const LIB_PIN* other = static_cast<const LIB_PIN*>( &aOther );
|
||||
|
||||
if( m_name != other->m_name )
|
||||
return false;
|
||||
|
||||
if( m_number != other->m_number )
|
||||
return false;
|
||||
|
||||
if( m_position != other->m_position )
|
||||
return false;
|
||||
|
||||
if( m_length != other->m_length )
|
||||
return false;
|
||||
|
||||
if( m_orientation != other->m_orientation )
|
||||
return false;
|
||||
|
||||
if( m_shape != other->m_shape )
|
||||
return false;
|
||||
|
||||
if( m_type != other->m_type )
|
||||
return false;
|
||||
|
||||
if( m_attributes != other->m_attributes )
|
||||
return false;
|
||||
|
||||
if( m_numTextSize != other->m_numTextSize )
|
||||
return false;
|
||||
|
||||
if( m_nameTextSize != other->m_nameTextSize )
|
||||
return false;
|
||||
|
||||
if( m_alternates.size() != other->m_alternates.size() )
|
||||
return false;
|
||||
|
||||
auto lhsItem = m_alternates.begin();
|
||||
auto rhsItem = other->m_alternates.begin();
|
||||
|
||||
while( lhsItem != m_alternates.end() )
|
||||
{
|
||||
if( rhsItem == other->m_alternates.end() )
|
||||
return false;
|
||||
|
||||
const ALT& lhsAlt = lhsItem->second;
|
||||
const ALT& rhsAlt = rhsItem->second;
|
||||
|
||||
if( lhsAlt.m_Name != rhsAlt.m_Name )
|
||||
return false;
|
||||
|
||||
if( lhsAlt.m_Type != rhsAlt.m_Type )
|
||||
return false;
|
||||
|
||||
if( lhsAlt.m_Shape != rhsAlt.m_Shape )
|
||||
return false;
|
||||
|
||||
++lhsItem;
|
||||
++rhsItem;
|
||||
}
|
||||
|
||||
return rhsItem == other->m_alternates.end();
|
||||
}
|
||||
|
||||
|
||||
double LIB_PIN::Similarity( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.m_Uuid == m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( aOther.Type() != LIB_PIN_T )
|
||||
return 0.0;
|
||||
|
||||
const LIB_PIN* other = static_cast<const LIB_PIN*>( &aOther );
|
||||
|
||||
double similarity = SimilarityBase( aOther );
|
||||
|
||||
if( m_name != other->m_name )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_number != other->m_number )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_position != other->m_position )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_length != other->m_length )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_orientation != other->m_orientation )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_shape != other->m_shape )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_type != other->m_type )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_attributes != other->m_attributes )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_numTextSize != other->m_numTextSize )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_nameTextSize != other->m_nameTextSize )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_alternates.size() != other->m_alternates.size() )
|
||||
similarity *= 0.9;
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& LIB_PIN::operator<<( std::ostream& aStream )
|
||||
{
|
||||
aStream << "LIB_PIN:" << std::endl
|
||||
|
|
|
@ -265,6 +265,13 @@ public:
|
|||
*/
|
||||
static const wxString GetCanonicalElectricalTypeName( ELECTRICAL_PINTYPE aType );
|
||||
|
||||
double Similarity( const LIB_ITEM& aItem ) const override;
|
||||
|
||||
bool operator==( const LIB_ITEM& aItem ) const override;
|
||||
bool operator!=( const LIB_ITEM& aItem ) const { return !operator==( aItem ); }
|
||||
bool operator<( const LIB_PIN& aRhs ) const { return compare( aRhs, EQUALITY ) < 0; }
|
||||
bool operator>( const LIB_PIN& aRhs ) const { return compare( aRhs, EQUALITY ) > 0; }
|
||||
|
||||
protected:
|
||||
struct EXTENTS_CACHE
|
||||
{
|
||||
|
@ -300,10 +307,6 @@ protected:
|
|||
*/
|
||||
void printPinElectricalTypeName( const RENDER_SETTINGS* aSettings, VECTOR2I& aPosition,
|
||||
PIN_ORIENTATION aOrientation, bool aDimmed );
|
||||
|
||||
bool operator==( const LIB_PIN& aRhs ) const { return compare( aRhs, EQUALITY ) == 0; }
|
||||
bool operator<( const LIB_PIN& aRhs ) const { return compare( aRhs, EQUALITY ) < 0; }
|
||||
bool operator>( const LIB_PIN& aRhs ) const { return compare( aRhs, EQUALITY ) > 0; }
|
||||
std::ostream& operator<<( std::ostream& aStream );
|
||||
|
||||
private:
|
||||
|
|
|
@ -518,6 +518,33 @@ void LIB_SHAPE::AddPoint( const VECTOR2I& aPosition )
|
|||
}
|
||||
|
||||
|
||||
bool LIB_SHAPE::operator==( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != Type() )
|
||||
return false;
|
||||
|
||||
const LIB_SHAPE& other = static_cast<const LIB_SHAPE&>( aOther );
|
||||
|
||||
return LIB_ITEM::operator==( aOther ) && EDA_SHAPE::operator==( other );
|
||||
}
|
||||
|
||||
|
||||
double LIB_SHAPE::Similarity( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( aOther.Type() != Type() )
|
||||
return 0.0;
|
||||
|
||||
const LIB_SHAPE& other = static_cast<const LIB_SHAPE&>( aOther );
|
||||
|
||||
double similarity = SimilarityBase( other );
|
||||
|
||||
similarity *= EDA_SHAPE::Similarity( other );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
void LIB_SHAPE::ViewGetLayers( int aLayers[], int& aCount ) const
|
||||
|
|
|
@ -120,6 +120,10 @@ public:
|
|||
|
||||
void ViewGetLayers( int aLayers[], int& aCount ) const override;
|
||||
|
||||
double Similarity( const LIB_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const LIB_ITEM& aOther ) const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @copydoc LIB_ITEM::compare()
|
||||
|
|
|
@ -1912,3 +1912,139 @@ std::vector<struct LIB_SYMBOL_UNIT> LIB_SYMBOL::GetUniqueUnits()
|
|||
|
||||
return uniqueUnits;
|
||||
}
|
||||
|
||||
|
||||
bool LIB_SYMBOL::operator==( const LIB_SYMBOL& aOther ) const
|
||||
{
|
||||
if( m_libId != aOther.m_libId )
|
||||
return false;
|
||||
|
||||
if( m_excludedFromBoard != aOther.m_excludedFromBoard )
|
||||
return false;
|
||||
|
||||
if( m_excludedFromBOM != aOther.m_excludedFromBOM )
|
||||
return false;
|
||||
|
||||
if( m_excludedFromSim != aOther.m_excludedFromSim )
|
||||
return false;
|
||||
|
||||
if( m_flags != aOther.m_flags )
|
||||
return false;
|
||||
|
||||
if( m_unitCount != aOther.m_unitCount )
|
||||
return false;
|
||||
|
||||
if( m_pinNameOffset != aOther.m_pinNameOffset )
|
||||
return false;
|
||||
|
||||
if( m_showPinNames != aOther.m_showPinNames )
|
||||
return false;
|
||||
|
||||
if( m_showPinNumbers != aOther.m_showPinNumbers )
|
||||
return false;
|
||||
|
||||
if( m_drawings.size() != aOther.m_drawings.size() )
|
||||
return false;
|
||||
|
||||
for( auto it1 = m_drawings.begin(), it2 = aOther.m_drawings.begin();
|
||||
it1 != m_drawings.end(); ++it1, ++it2 )
|
||||
{
|
||||
if( !( *it1 == *it2 ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
const LIB_PINS thisPinList = GetAllLibPins();
|
||||
const LIB_PINS otherPinList = aOther.GetAllLibPins();
|
||||
|
||||
if( thisPinList.size() != otherPinList.size() )
|
||||
return false;
|
||||
|
||||
for( auto it1 = thisPinList.begin(), it2 = otherPinList.begin();
|
||||
it1 != thisPinList.end(); ++it1, ++it2 )
|
||||
{
|
||||
if( !( **it1 == **it2 ) )
|
||||
return false;
|
||||
}
|
||||
for( size_t ii = 0; ii < thisPinList.size(); ++ii )
|
||||
{
|
||||
if( !( *thisPinList[ii] == *otherPinList[ii] ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double LIB_SYMBOL::Similarity( const LIB_SYMBOL& aOther ) const
|
||||
{
|
||||
double similarity = 0.0;
|
||||
int totalItems = 0;
|
||||
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
for( const LIB_ITEM& item : m_drawings )
|
||||
{
|
||||
totalItems += 1;
|
||||
double max_similarity = 0.0;
|
||||
|
||||
for( const LIB_ITEM& otherItem : aOther.m_drawings )
|
||||
{
|
||||
double temp_similarity = item.Similarity( otherItem );
|
||||
max_similarity = std::max( max_similarity, temp_similarity );
|
||||
|
||||
if( max_similarity == 1.0 )
|
||||
break;
|
||||
}
|
||||
|
||||
similarity += max_similarity;
|
||||
}
|
||||
|
||||
for( const LIB_PIN* pin : GetAllLibPins() )
|
||||
{
|
||||
totalItems += 1;
|
||||
double max_similarity = 0.0;
|
||||
|
||||
for( const LIB_PIN* otherPin : aOther.GetAllLibPins() )
|
||||
{
|
||||
double temp_similarity = pin->Similarity( *otherPin );
|
||||
max_similarity = std::max( max_similarity, temp_similarity );
|
||||
|
||||
if( max_similarity == 1.0 )
|
||||
break;
|
||||
}
|
||||
|
||||
similarity += max_similarity;
|
||||
}
|
||||
|
||||
if( totalItems == 0 )
|
||||
similarity = 0.0;
|
||||
else
|
||||
similarity /= totalItems;
|
||||
|
||||
if( m_excludedFromBoard != aOther.m_excludedFromBoard )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_excludedFromBOM != aOther.m_excludedFromBOM )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_excludedFromSim != aOther.m_excludedFromSim )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_flags != aOther.m_flags )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_unitCount != aOther.m_unitCount )
|
||||
similarity *= 0.5;
|
||||
|
||||
if( m_pinNameOffset != aOther.m_pinNameOffset )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_showPinNames != aOther.m_showPinNames )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_showPinNumbers != aOther.m_showPinNumbers )
|
||||
similarity *= 0.9;
|
||||
|
||||
return similarity;
|
||||
}
|
|
@ -711,11 +711,7 @@ public:
|
|||
REPORTER* aReporter = nullptr ) const;
|
||||
|
||||
bool operator==( const LIB_SYMBOL* aSymbol ) const { return this == aSymbol; }
|
||||
bool operator==( const LIB_SYMBOL& aSymbol ) const
|
||||
{
|
||||
return Compare( aSymbol, LIB_ITEM::COMPARE_FLAGS::EQUALITY ) == 0;
|
||||
}
|
||||
|
||||
bool operator==( const LIB_SYMBOL& aSymbol ) const;
|
||||
bool operator!=( const LIB_SYMBOL& aSymbol ) const
|
||||
{
|
||||
return Compare( aSymbol, LIB_ITEM::COMPARE_FLAGS::EQUALITY ) != 0;
|
||||
|
@ -762,6 +758,13 @@ public:
|
|||
*/
|
||||
std::vector<LIB_ITEM*> GetUnitDrawItems( int aUnit, int aConvert );
|
||||
|
||||
/**
|
||||
* Return a measure of similarity between this symbol and \a aSymbol.
|
||||
* @param aSymbol is the symbol to compare to.
|
||||
*
|
||||
* @return a measure of similarity from 1.0 (identical) to 0.0 (no similarity).
|
||||
*/
|
||||
double Similarity( const LIB_SYMBOL& aSymbol ) const;
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
|
|
@ -500,6 +500,33 @@ void LIB_TEXT::CalcEdit( const VECTOR2I& aPosition )
|
|||
}
|
||||
|
||||
|
||||
bool LIB_TEXT::operator==( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return false;
|
||||
|
||||
const LIB_TEXT& other = static_cast<const LIB_TEXT&>( aOther );
|
||||
|
||||
return LIB_ITEM::operator==( aOther ) && EDA_TEXT::operator==( other );
|
||||
}
|
||||
|
||||
|
||||
double LIB_TEXT::Similarity( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( aOther.Type() != Type() )
|
||||
return 0.0;
|
||||
|
||||
const LIB_TEXT& other = static_cast<const LIB_TEXT&>( aOther );
|
||||
|
||||
double similarity = SimilarityBase( other );
|
||||
similarity *= EDA_TEXT::Similarity( other );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
static struct LIB_TEXT_DESC
|
||||
{
|
||||
LIB_TEXT_DESC()
|
||||
|
|
|
@ -113,6 +113,10 @@ public:
|
|||
|
||||
EDA_ITEM* Clone() const override;
|
||||
|
||||
double Similarity( const LIB_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const LIB_ITEM& aOther ) const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @copydoc LIB_ITEM::compare()
|
||||
|
|
|
@ -501,6 +501,35 @@ void LIB_TEXTBOX::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL
|
|||
}
|
||||
|
||||
|
||||
bool LIB_TEXTBOX::operator==( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != LIB_TEXTBOX_T )
|
||||
return false;
|
||||
|
||||
const LIB_TEXTBOX& other = static_cast<const LIB_TEXTBOX&>( aOther );
|
||||
|
||||
return LIB_SHAPE::operator==( other ) && EDA_TEXT::operator==( other );
|
||||
}
|
||||
|
||||
|
||||
double LIB_TEXTBOX::Similarity( const LIB_ITEM& aOther ) const
|
||||
{
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( aOther.Type() != LIB_TEXTBOX_T )
|
||||
return 0.0;
|
||||
|
||||
const LIB_TEXTBOX& other = static_cast<const LIB_TEXTBOX&>( aOther );
|
||||
|
||||
double similarity = SimilarityBase( other );
|
||||
similarity *= LIB_SHAPE::Similarity( other );
|
||||
similarity *= EDA_TEXT::Similarity( other );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
void LIB_TEXTBOX::ViewGetLayers( int aLayers[], int& aCount ) const
|
||||
{
|
||||
aCount = 3;
|
||||
|
|
|
@ -93,6 +93,10 @@ public:
|
|||
|
||||
void ViewGetLayers( int aLayers[], int& aCount ) const override;
|
||||
|
||||
double Similarity( const LIB_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const LIB_ITEM& aOther ) const override;
|
||||
|
||||
protected:
|
||||
KIFONT::FONT* getDrawFont() const override;
|
||||
|
||||
|
|
|
@ -249,3 +249,45 @@ static struct SCH_BITMAP_DESC
|
|||
propMgr.InheritsAfter( TYPE_HASH( SCH_BITMAP ), TYPE_HASH( SCH_ITEM ) );
|
||||
}
|
||||
} _SCH_BITMAP_DESC;
|
||||
|
||||
|
||||
bool SCH_BITMAP::operator==( const SCH_ITEM& aItem ) const
|
||||
{
|
||||
if( Type() != aItem.Type() )
|
||||
return false;
|
||||
|
||||
const SCH_BITMAP* bitmap = static_cast<const SCH_BITMAP*>( &aItem );
|
||||
|
||||
if( GetPosition() != bitmap->GetPosition() )
|
||||
return false;
|
||||
|
||||
if( GetSize() != bitmap->GetSize() )
|
||||
return false;
|
||||
|
||||
if( GetImage() != bitmap->GetImage() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_BITMAP::Similarity( const SCH_ITEM& aItem ) const
|
||||
{
|
||||
if( Type() != aItem.Type() )
|
||||
return 0.0;
|
||||
|
||||
if( m_Uuid == aItem.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
const SCH_BITMAP* bitmap = static_cast<const SCH_BITMAP*>( &aItem );
|
||||
|
||||
if( GetImage() != bitmap->GetImage() )
|
||||
return 0.0;
|
||||
|
||||
// If it is the same image but a different UUID and a different size,
|
||||
// then it _might be different_.
|
||||
if( GetSize() != bitmap->GetSize() )
|
||||
return 0.5;
|
||||
|
||||
return 1.0;
|
||||
}
|
|
@ -154,6 +154,10 @@ public:
|
|||
|
||||
EDA_ITEM* Clone() const override;
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override;
|
||||
#endif
|
||||
|
|
|
@ -577,6 +577,45 @@ bool SCH_BUS_WIRE_ENTRY::ConnectionPropagatesTo( const EDA_ITEM* aItem ) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SCH_BUS_ENTRY_BASE::operator==( const SCH_ITEM& aItem ) const
|
||||
{
|
||||
if( Type() != aItem.Type() )
|
||||
return false;
|
||||
|
||||
const SCH_BUS_ENTRY_BASE* symbol = static_cast<const SCH_BUS_ENTRY_BASE*>( &aItem );
|
||||
|
||||
if( GetLayer() != symbol->GetLayer() )
|
||||
return false;
|
||||
|
||||
if( GetPosition() != symbol->GetPosition() )
|
||||
return false;
|
||||
|
||||
if( GetEnd() != symbol->GetEnd() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_BUS_ENTRY_BASE::Similarity( const SCH_ITEM& aItem ) const
|
||||
{
|
||||
if( aItem.Type() != Type() )
|
||||
return 0.0;
|
||||
|
||||
if( m_Uuid == aItem.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
const SCH_BUS_ENTRY_BASE& other = static_cast<const SCH_BUS_ENTRY_BASE&>( aItem );
|
||||
|
||||
if( GetLayer() != other.GetLayer() )
|
||||
return 0.0;
|
||||
|
||||
if( GetPosition() != other.GetPosition() )
|
||||
return 0.0;
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_BUS_ENTRY_DESC
|
||||
{
|
||||
|
|
|
@ -128,6 +128,10 @@ public:
|
|||
|
||||
bool operator <( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
double Similarity( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
|
|
@ -1294,6 +1294,74 @@ bool SCH_FIELD::operator <( const SCH_ITEM& aItem ) const
|
|||
return GetName() < field->GetName();
|
||||
}
|
||||
|
||||
bool SCH_FIELD::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return false;
|
||||
|
||||
const SCH_FIELD& field = static_cast<const SCH_FIELD&>( aOther );
|
||||
|
||||
if( GetId() != field.GetId() )
|
||||
return false;
|
||||
|
||||
if( GetPosition() != field.GetPosition() )
|
||||
return false;
|
||||
|
||||
if( IsNamedVariable() != field.IsNamedVariable() )
|
||||
return false;
|
||||
|
||||
if( IsNameShown() != field.IsNameShown() )
|
||||
return false;
|
||||
|
||||
if( CanAutoplace() != field.CanAutoplace() )
|
||||
return false;
|
||||
|
||||
if( GetText() != field.GetText() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_FIELD::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return 0.0;
|
||||
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
const SCH_FIELD& field = static_cast<const SCH_FIELD&>( aOther );
|
||||
|
||||
double retval = 0.99; // The UUIDs are different, so we start with non-identity
|
||||
|
||||
if( GetId() != field.GetId() )
|
||||
{
|
||||
// We don't allow swapping of mandatory fields, so these cannot be the same item
|
||||
if( GetId() < MANDATORY_FIELDS || field.GetId() < MANDATORY_FIELDS )
|
||||
return 0.0;
|
||||
else
|
||||
retval *= 0.5;
|
||||
}
|
||||
|
||||
if( GetPosition() != field.GetPosition() )
|
||||
retval *= 0.5;
|
||||
|
||||
if( IsNamedVariable() != field.IsNamedVariable() )
|
||||
retval *= 0.5;
|
||||
|
||||
if( IsNameShown() != field.IsNameShown() )
|
||||
retval *= 0.5;
|
||||
|
||||
if( CanAutoplace() != field.CanAutoplace() )
|
||||
retval *= 0.5;
|
||||
|
||||
if( GetText() != field.GetText() )
|
||||
retval *= Levenshtein( field );
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_FIELD_DESC
|
||||
{
|
||||
|
|
|
@ -275,6 +275,10 @@ public:
|
|||
|
||||
bool operator <( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
double Similarity( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
|
|
@ -279,6 +279,15 @@ public:
|
|||
|
||||
bool RenderAsBitmap( double aWorldScale ) const override;
|
||||
|
||||
/**
|
||||
* Return a measure of how likely the other object is to represent the same
|
||||
* object. The scale runs from 0.0 (definitely different objects) to 1.0 (same)
|
||||
*
|
||||
* This is a pure virtual function. Derived classes must implement this.
|
||||
*/
|
||||
virtual double Similarity( const SCH_ITEM& aItem ) const = 0;
|
||||
virtual bool operator==( const SCH_ITEM& aItem ) const = 0;
|
||||
|
||||
/**
|
||||
* Print a schematic item.
|
||||
*
|
||||
|
|
|
@ -307,6 +307,51 @@ void SCH_JUNCTION::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANE
|
|||
}
|
||||
|
||||
|
||||
bool SCH_JUNCTION::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return false;
|
||||
|
||||
const SCH_JUNCTION& other = static_cast<const SCH_JUNCTION&>( aOther );
|
||||
|
||||
if( m_pos != other.m_pos )
|
||||
return false;
|
||||
|
||||
if( m_diameter != other.m_diameter )
|
||||
return false;
|
||||
|
||||
if( m_color != other.m_color )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_JUNCTION::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( aOther.Type() != Type() )
|
||||
return 0.0;
|
||||
|
||||
const SCH_JUNCTION& other = static_cast<const SCH_JUNCTION&>( aOther );
|
||||
|
||||
double similarity = 1.0;
|
||||
|
||||
if( m_pos != other.m_pos )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_diameter != other.m_diameter )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_color != other.m_color )
|
||||
similarity *= 0.9;
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_JUNCTION_DESC
|
||||
{
|
||||
SCH_JUNCTION_DESC()
|
||||
|
|
|
@ -129,6 +129,10 @@ public:
|
|||
|
||||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override;
|
||||
#endif
|
||||
|
|
|
@ -579,6 +579,69 @@ bool SCH_LABEL_BASE::IncrementLabel( int aIncrement )
|
|||
}
|
||||
|
||||
|
||||
bool SCH_LABEL_BASE::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
const SCH_LABEL_BASE* other = dynamic_cast<const SCH_LABEL_BASE*>( &aOther );
|
||||
|
||||
if( !other )
|
||||
return false;
|
||||
|
||||
if( m_shape != other->m_shape )
|
||||
return false;
|
||||
|
||||
if( m_connectionType != other->m_connectionType )
|
||||
return false;
|
||||
|
||||
if( m_fields.size() != other->m_fields.size() )
|
||||
return false;
|
||||
|
||||
for( size_t ii = 0; ii < m_fields.size(); ++ii )
|
||||
{
|
||||
if( !( m_fields[ii] == other->m_fields[ii] ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return SCH_TEXT::operator==( aOther );
|
||||
}
|
||||
|
||||
|
||||
double SCH_LABEL_BASE::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
const SCH_LABEL_BASE* other = dynamic_cast<const SCH_LABEL_BASE*>( &aOther );
|
||||
|
||||
if( !other )
|
||||
return 0.0;
|
||||
|
||||
if( m_Uuid == other->m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
double similarity = SCH_TEXT::Similarity( aOther );
|
||||
|
||||
if( typeid( *this ) != typeid( aOther ) )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_shape == other->m_shape )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_connectionType == other->m_connectionType )
|
||||
similarity *= 0.9;
|
||||
|
||||
for( size_t ii = 0; ii < m_fields.size(); ++ii )
|
||||
{
|
||||
if( ii >= other->m_fields.size() )
|
||||
break;
|
||||
|
||||
similarity *= m_fields[ii].Similarity( other->m_fields[ii] );
|
||||
}
|
||||
|
||||
int diff = std::abs( int( m_fields.size() ) - int( other->m_fields.size() ) );
|
||||
|
||||
similarity *= std::pow( 0.9, diff );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
void SCH_LABEL_BASE::AutoplaceFields( SCH_SCREEN* aScreen, bool aManual )
|
||||
{
|
||||
int margin = GetTextOffset() * 2;
|
||||
|
|
|
@ -311,6 +311,10 @@ public:
|
|||
*/
|
||||
virtual bool AutoRotateOnPlacementSupported() const = 0;
|
||||
|
||||
double Similarity( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
protected:
|
||||
void cacheShownText() override;
|
||||
|
||||
|
|
|
@ -978,6 +978,69 @@ bool SCH_LINE::IsBus() const
|
|||
}
|
||||
|
||||
|
||||
bool SCH_LINE::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return false;
|
||||
|
||||
const SCH_LINE& other = static_cast<const SCH_LINE&>( aOther );
|
||||
|
||||
if( GetLayer() != other.GetLayer() )
|
||||
return false;
|
||||
|
||||
if( m_start != other.m_start )
|
||||
return false;
|
||||
|
||||
if( m_end != other.m_end )
|
||||
return false;
|
||||
|
||||
if( m_stroke.GetWidth() != other.m_stroke.GetWidth() )
|
||||
return false;
|
||||
|
||||
if( m_stroke.GetColor() != other.m_stroke.GetColor() )
|
||||
return false;
|
||||
|
||||
if( m_stroke.GetPlotStyle() != other.m_stroke.GetPlotStyle() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_LINE::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( Type() != aOther.Type() )
|
||||
return 0.0;
|
||||
|
||||
const SCH_LINE& other = static_cast<const SCH_LINE&>( aOther );
|
||||
|
||||
if( GetLayer() != other.GetLayer() )
|
||||
return 0.0;
|
||||
|
||||
double similarity = 1.0;
|
||||
|
||||
if( m_start != other.m_start )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_end != other.m_end )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_stroke.GetWidth() != other.m_stroke.GetWidth() )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_stroke.GetColor() != other.m_stroke.GetColor() )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_stroke.GetPlotStyle() != other.m_stroke.GetPlotStyle() )
|
||||
similarity *= 0.9;
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_LINE_DESC
|
||||
{
|
||||
SCH_LINE_DESC()
|
||||
|
|
|
@ -326,6 +326,10 @@ public:
|
|||
*/
|
||||
bool IsBus() const;
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Recursively called function to travel through the connected wires and find a connected
|
||||
|
|
|
@ -120,6 +120,16 @@ public:
|
|||
*/
|
||||
bool IsLegacyMarker() const { return m_isLegacyMarker; }
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override;
|
||||
#endif
|
||||
|
|
|
@ -195,3 +195,34 @@ BITMAPS SCH_NO_CONNECT::GetMenuImage() const
|
|||
{
|
||||
return BITMAPS::noconn;
|
||||
}
|
||||
|
||||
|
||||
bool SCH_NO_CONNECT::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != Type() )
|
||||
return false;
|
||||
|
||||
const SCH_NO_CONNECT* other = static_cast<const SCH_NO_CONNECT*>( &aOther );
|
||||
|
||||
if( m_pos != other->m_pos )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_NO_CONNECT::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( aOther.Type() != Type() )
|
||||
return 0.0;
|
||||
|
||||
const SCH_NO_CONNECT* other = static_cast<const SCH_NO_CONNECT*>( &aOther );
|
||||
|
||||
if( m_pos != other->m_pos )
|
||||
return 0.0;
|
||||
|
||||
return 1.0;
|
||||
}
|
|
@ -109,6 +109,10 @@ public:
|
|||
|
||||
EDA_ITEM* Clone() const override;
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
|
|
@ -416,6 +416,43 @@ bool SCH_PIN::ConnectionPropagatesTo( const EDA_ITEM* aItem ) const
|
|||
}
|
||||
|
||||
|
||||
bool SCH_PIN::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != SCH_PIN_T )
|
||||
return false;
|
||||
|
||||
const SCH_PIN& other = static_cast<const SCH_PIN&>( aOther );
|
||||
|
||||
if( m_number != other.m_number )
|
||||
return false;
|
||||
|
||||
if( m_position != other.m_position )
|
||||
return false;
|
||||
|
||||
return m_libPin == other.m_libPin;
|
||||
}
|
||||
|
||||
|
||||
double SCH_PIN::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( m_Uuid == aOther.m_Uuid )
|
||||
return 1.0;
|
||||
|
||||
if( aOther.Type() != SCH_PIN_T )
|
||||
return 0.0;
|
||||
|
||||
const SCH_PIN& other = static_cast<const SCH_PIN&>( aOther );
|
||||
|
||||
if( m_number != other.m_number )
|
||||
return 0.0;
|
||||
|
||||
if( m_position != other.m_position )
|
||||
return 0.0;
|
||||
|
||||
return m_libPin->Similarity( *other.m_libPin );
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_PIN_DESC
|
||||
{
|
||||
SCH_PIN_DESC()
|
||||
|
|
|
@ -164,6 +164,10 @@ public:
|
|||
const wxString& GetOperatingPoint() const { return m_operatingPoint; }
|
||||
void SetOperatingPoint( const wxString& aText ) { m_operatingPoint = aText; }
|
||||
|
||||
double Similarity( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aItem ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override {}
|
||||
#endif
|
||||
|
|
|
@ -502,6 +502,30 @@ void SCH_SHAPE::AddPoint( const VECTOR2I& aPosition )
|
|||
}
|
||||
|
||||
|
||||
bool SCH_SHAPE::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != Type() )
|
||||
return false;
|
||||
|
||||
const SCH_SHAPE& other = static_cast<const SCH_SHAPE&>( aOther );
|
||||
|
||||
return EDA_SHAPE::operator==( other );
|
||||
}
|
||||
|
||||
|
||||
double SCH_SHAPE::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != Type() )
|
||||
return 0.0;
|
||||
|
||||
const SCH_SHAPE& other = static_cast<const SCH_SHAPE&>( aOther );
|
||||
|
||||
double similarity = EDA_SHAPE::Similarity( other );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_SHAPE_DESC
|
||||
{
|
||||
SCH_SHAPE_DESC()
|
||||
|
|
|
@ -107,6 +107,10 @@ public:
|
|||
|
||||
void ViewGetLayers( int aLayers[], int& aCount ) const override;
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
|
|
@ -1387,6 +1387,55 @@ int SCH_SHEET::ComparePageNum( const wxString& aPageNumberA, const wxString& aPa
|
|||
}
|
||||
|
||||
|
||||
bool SCH_SHEET::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return false;
|
||||
|
||||
const SCH_SHEET* other = static_cast<const SCH_SHEET*>( &aOther );
|
||||
|
||||
if( m_pos != other->m_pos )
|
||||
return false;
|
||||
|
||||
if( m_size != other->m_size )
|
||||
return false;
|
||||
|
||||
if( GetBorderColor() != other->GetBorderColor() )
|
||||
return false;
|
||||
|
||||
if( GetBackgroundColor() != other->GetBackgroundColor() )
|
||||
return false;
|
||||
|
||||
if( GetBorderWidth() != other->GetBorderWidth() )
|
||||
return false;
|
||||
|
||||
if( GetFields().size() != other->GetFields().size() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < GetFields().size(); ++i )
|
||||
{
|
||||
if( !( GetFields()[i] == other->GetFields()[i] ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_SHEET::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return 0.0;
|
||||
|
||||
const SCH_SHEET* other = static_cast<const SCH_SHEET*>( &aOther );
|
||||
|
||||
if( m_screen->GetFileName() == other->m_screen->GetFileName() )
|
||||
return 1.0;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
void SCH_SHEET::Show( int nestLevel, std::ostream& os ) const
|
||||
|
|
|
@ -418,6 +418,10 @@ public:
|
|||
*/
|
||||
static int ComparePageNum( const wxString& aPageNumberA, const wxString& aPageNumberB );
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int nestLevel, std::ostream& os ) const override;
|
||||
#endif
|
||||
|
|
|
@ -80,6 +80,16 @@ public:
|
|||
void MirrorVertically( int aCenter ) override {}
|
||||
void Rotate( const VECTOR2I& aCenter ) override {}
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int , std::ostream& ) const override {}
|
||||
#endif
|
||||
|
|
|
@ -356,6 +356,39 @@ bool SCH_SHEET_PIN::HitTest( const VECTOR2I& aPoint, int aAccuracy ) const
|
|||
}
|
||||
|
||||
|
||||
bool SCH_SHEET_PIN::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != Type() )
|
||||
return false;
|
||||
|
||||
const SCH_SHEET_PIN* other = static_cast<const SCH_SHEET_PIN*>( &aOther );
|
||||
|
||||
return m_edge == other->m_edge && m_number == other->m_number
|
||||
&& SCH_HIERLABEL::operator==( aOther );
|
||||
}
|
||||
|
||||
|
||||
double SCH_SHEET_PIN::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( aOther.Type() != Type() )
|
||||
return 0.0;
|
||||
|
||||
const SCH_SHEET_PIN* other = static_cast<const SCH_SHEET_PIN*>( &aOther );
|
||||
|
||||
double similarity = 1.0;
|
||||
|
||||
if( m_edge != other->m_edge )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_number != other->m_number )
|
||||
similarity *= 0.9;
|
||||
|
||||
similarity *= SCH_HIERLABEL::Similarity( aOther );
|
||||
|
||||
return similarity;
|
||||
}
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
void SCH_SHEET_PIN::Show( int nestLevel, std::ostream& os ) const
|
||||
|
|
|
@ -200,6 +200,10 @@ public:
|
|||
|
||||
EDA_ITEM* Clone() const override;
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
private:
|
||||
int m_number; ///< Label number use for saving sheet label to file.
|
||||
///< Sheet label numbering begins at 2.
|
||||
|
|
|
@ -2519,6 +2519,61 @@ bool SCH_SYMBOL::IsPower() const
|
|||
}
|
||||
|
||||
|
||||
bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return false;
|
||||
|
||||
auto symbol = static_cast<const SCH_SYMBOL&>( aOther );
|
||||
|
||||
if( GetLibId() != symbol.GetLibId() )
|
||||
return false;
|
||||
|
||||
if( GetPosition() != symbol.GetPosition() )
|
||||
return false;
|
||||
|
||||
if( GetUnit() != symbol.GetUnit() )
|
||||
return false;
|
||||
|
||||
if( GetConvert() != symbol.GetConvert() )
|
||||
return false;
|
||||
|
||||
if( GetTransform() != symbol.GetTransform() )
|
||||
return false;
|
||||
|
||||
if( GetFields() != symbol.GetFields() )
|
||||
return false;
|
||||
|
||||
if( m_pins.size() != symbol.m_pins.size() )
|
||||
return false;
|
||||
|
||||
for( unsigned i = 0; i < m_pins.size(); ++i )
|
||||
{
|
||||
if( !( *m_pins[i] == *symbol.m_pins[i] ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
|
||||
{
|
||||
if( Type() != aOther.Type() )
|
||||
return 0.0;
|
||||
|
||||
auto symbol = static_cast<const SCH_SYMBOL&>( aOther );
|
||||
|
||||
if( GetLibId() != symbol.GetLibId() )
|
||||
return 0.0;
|
||||
|
||||
if( GetPosition() == symbol.GetPosition() )
|
||||
return 1.0;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_SYMBOL_DESC
|
||||
{
|
||||
SCH_SYMBOL_DESC()
|
||||
|
|
|
@ -758,6 +758,10 @@ public:
|
|||
|
||||
bool IsPower() const;
|
||||
|
||||
double Similarity( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
bool operator==( const SCH_ITEM& aOther ) const override;
|
||||
|
||||
private:
|
||||
BOX2I doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue