ADDED: Project chooser dialog for EasyEDA Pro import.

This commit is contained in:
Alex Shvartzkop 2023-10-30 09:34:45 +03:00
parent 1b9062bd9f
commit 847ab093c8
22 changed files with 895 additions and 77 deletions

View File

@ -225,6 +225,8 @@ set( COMMON_DLG_SRCS
dialogs/dialog_grid_settings_base.cpp
dialogs/dialog_hotkey_list.cpp
dialogs/dialog_HTML_reporter_base.cpp
dialogs/dialog_import_choose_project.cpp
dialogs/dialog_import_choose_project_base.cpp
dialogs/dialog_locked_items_query.cpp
dialogs/dialog_locked_items_query_base.cpp
dialogs/dialog_migrate_settings.cpp

View File

@ -0,0 +1,112 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <dialog_import_choose_project.h>
#include <wx/msgdlg.h>
#include <wx/listctrl.h>
DIALOG_IMPORT_CHOOSE_PROJECT::DIALOG_IMPORT_CHOOSE_PROJECT(
wxWindow* aParent, const std::vector<IMPORT_PROJECT_DESC>& aProjectDesc ) :
DIALOG_IMPORT_CHOOSE_PROJECT_BASE( aParent )
{
m_project_desc = aProjectDesc;
// Initialize columns in the wxListCtrl elements:
int comboNameColId = m_listCtrl->AppendColumn( _( "Project Name" ) );
int pcbNameColId = m_listCtrl->AppendColumn( _( "PCB" ) );
int schNameColId = m_listCtrl->AppendColumn( _( "Schematic" ) );
// Load the project/PCB/schematic names
int row = 0;
auto convertName = []( const wxString& aName, const wxString& aId ) -> wxString
{
if( aId.empty() )
return wxEmptyString;
return aName;
};
for( const IMPORT_PROJECT_DESC& desc : m_project_desc )
{
m_listCtrl->InsertItem( row, convertName( desc.ComboName, desc.ComboId ) );
m_listCtrl->SetItem( row, pcbNameColId, convertName( desc.PCBName, desc.PCBId ) );
m_listCtrl->SetItem( row, schNameColId,
convertName( desc.SchematicName, desc.SchematicId ) );
++row;
}
// Auto select the first item to improve ease-of-use
m_listCtrl->SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
m_listCtrl->SetColumnWidth( comboNameColId, wxLIST_AUTOSIZE_USEHEADER );
m_listCtrl->SetColumnWidth( pcbNameColId, wxLIST_AUTOSIZE_USEHEADER );
m_listCtrl->SetColumnWidth( schNameColId, wxLIST_AUTOSIZE_USEHEADER );
SetupStandardButtons();
Fit();
finishDialogSettings();
}
void DIALOG_IMPORT_CHOOSE_PROJECT::onItemActivated( wxListEvent& event )
{
EndModal( wxID_OK );
}
void DIALOG_IMPORT_CHOOSE_PROJECT::onClose( wxCloseEvent& event )
{
EndModal( wxID_CANCEL );
}
std::vector<IMPORT_PROJECT_DESC> DIALOG_IMPORT_CHOOSE_PROJECT::GetProjectSelections()
{
std::vector<IMPORT_PROJECT_DESC> result;
long selected = -1;
do
{
selected = m_listCtrl->GetNextItem( selected, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
if( selected != -1 && selected < long( m_project_desc.size() ) )
result.emplace_back( m_project_desc[selected] );
} while( selected != -1 );
return result;
}
std::vector<IMPORT_PROJECT_DESC> DIALOG_IMPORT_CHOOSE_PROJECT::GetSelectionsModal(
wxWindow* aParent, const std::vector<IMPORT_PROJECT_DESC>& aProjectDesc )
{
DIALOG_IMPORT_CHOOSE_PROJECT dlg( aParent, aProjectDesc );
if( dlg.ShowModal() != wxID_OK )
return {};
return dlg.GetProjectSelections();
}

View File

@ -0,0 +1,53 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef DIALOG_IMPORT_CHOOSE_PROJECT_H
#define DIALOG_IMPORT_CHOOSE_PROJECT_H
#include "dialog_import_choose_project_base.h"
#include <plugins/common/plugin_common_choose_project.h>
class DIALOG_IMPORT_CHOOSE_PROJECT : public DIALOG_IMPORT_CHOOSE_PROJECT_BASE
{
public:
DIALOG_IMPORT_CHOOSE_PROJECT( wxWindow* aParent,
const std::vector<IMPORT_PROJECT_DESC>& aProjectDesc );
/**
* Create and show a dialog (modal) and returns the data from it after completion. If the
* dialog is closed or cancel is pressed, returns an empty vector.
*
* @param aParent Parent window for the invoked dialog.
* @param aProjectDesc are project descriptors.
*/
static std::vector<IMPORT_PROJECT_DESC>
GetSelectionsModal( wxWindow* aParent, const std::vector<IMPORT_PROJECT_DESC>& aProjectDesc );
void onItemActivated( wxListEvent& event ) override;
void onClose( wxCloseEvent& event ) override;
std::vector<IMPORT_PROJECT_DESC> GetProjectSelections();
private:
std::vector<IMPORT_PROJECT_DESC> m_project_desc;
};
#endif // DIALOG_IMPORT_CHOOSE_PROJECT_H

View File

@ -0,0 +1,54 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "dialog_import_choose_project_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_IMPORT_CHOOSE_PROJECT_BASE::DIALOG_IMPORT_CHOOSE_PROJECT_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 );
bSizerMain = new wxBoxSizer( wxVERTICAL );
m_titleText = new wxStaticText( this, wxID_ANY, _("This project file contains multiple PCB+Schematic combinations.\nChoose which one should be imported to KiCad."), wxDefaultPosition, wxDefaultSize, 0 );
m_titleText->Wrap( -1 );
bSizerMain->Add( m_titleText, 0, wxALL, 5 );
m_listCtrl = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES );
bSizerMain->Add( m_listCtrl, 1, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizerBottom;
bSizerBottom = new wxBoxSizer( wxHORIZONTAL );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
m_sdbSizer->Realize();
bSizerBottom->Add( m_sdbSizer, 1, wxEXPAND, 5 );
bSizerMain->Add( bSizerBottom, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );
this->SetSizer( bSizerMain );
this->Layout();
bSizerMain->Fit( this );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_IMPORT_CHOOSE_PROJECT_BASE::onClose ) );
m_listCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( DIALOG_IMPORT_CHOOSE_PROJECT_BASE::onItemActivated ), NULL, this );
}
DIALOG_IMPORT_CHOOSE_PROJECT_BASE::~DIALOG_IMPORT_CHOOSE_PROJECT_BASE()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_IMPORT_CHOOSE_PROJECT_BASE::onClose ) );
m_listCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( DIALOG_IMPORT_CHOOSE_PROJECT_BASE::onItemActivated ), NULL, this );
}

View File

@ -0,0 +1,221 @@
<?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">dialog_import_choose_project_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">dialog_import_choose_project_base</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="Dialog" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="center"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></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">-1,-1</property>
<property name="name">DIALOG_IMPORT_CHOOSE_PROJECT_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="style">wxCAPTION|wxCLOSE_BOX|wxRESIZE_BORDER</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title">Choose Project to Import</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"></property>
<event name="OnClose">onClose</event>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizerMain</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">protected</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" 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="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="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">This project file contains multiple PCB+Schematic combinations.&#x0A;Choose which one should be imported to KiCad.</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_titleText</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">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxListCtrl" 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="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="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_listCtrl</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">wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES</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="OnListItemActivated">onItemActivated</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizerBottom</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<property name="Apply">0</property>
<property name="Cancel">0</property>
<property name="ContextHelp">0</property>
<property name="Help">0</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<property name="minimum_size"></property>
<property name="name">m_sdbSizer</property>
<property name="permission">protected</property>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// 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/listctrl.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_IMPORT_CHOOSE_PROJECT_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_IMPORT_CHOOSE_PROJECT_BASE : public DIALOG_SHIM
{
private:
protected:
wxBoxSizer* bSizerMain;
wxStaticText* m_titleText;
wxListCtrl* m_listCtrl;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
// Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onItemActivated( wxListEvent& event ) { event.Skip(); }
public:
DIALOG_IMPORT_CHOOSE_PROJECT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Choose Project to Import"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxCAPTION|wxCLOSE_BOX|wxRESIZE_BORDER );
~DIALOG_IMPORT_CHOOSE_PROJECT_BASE();
};

View File

@ -0,0 +1,73 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGIN_COMMON_CHOOSE_PROJECT_H
#define PLUGIN_COMMON_CHOOSE_PROJECT_H
#include <functional>
#include <map>
/**
* @brief Describes how non-KiCad boards and schematics should be imported as KiCad projects
*/
struct IMPORT_PROJECT_DESC
{
wxString ComboName;
wxString PCBName;
wxString SchematicName;
wxString ComboId;
wxString PCBId;
wxString SchematicId;
IMPORT_PROJECT_DESC() {}
};
/**
* @brief Pointer to a function that takes descriptions of the source projects
* and removes the ones that are not needed, or clears their ID fields.
*/
using CHOOSE_PROJECT_HANDLER = std::function<std::vector<IMPORT_PROJECT_DESC>( const std::vector<IMPORT_PROJECT_DESC>& )>;
/**
* @brief Plugin class for import plugins that support choosing a project
*/
class PROJECT_CHOOSER_PLUGIN
{
public:
/**
* @brief Register a different handler to be called when a non-KiCad project
* contains multiple PCB+Schematic combinations.
*
* The function is marked as virtual, so the plugins can implement extra
* logic (e.g., enable warnings or checks)
*/
virtual void RegisterChooseProjectCallback( CHOOSE_PROJECT_HANDLER aChooseProjectHandler )
{
m_choose_project_handler = aChooseProjectHandler;
}
virtual ~PROJECT_CHOOSER_PLUGIN() = default;
protected:
CHOOSE_PROJECT_HANDLER m_choose_project_handler; ///< Callback to choose projects to import
};
#endif // PLUGIN_COMMON_CHOOSE_PROJECT_H

View File

@ -23,10 +23,14 @@
*/
#include "easyedapro_import_utils.h"
#include "easyedapro_parser.h"
#include <plugins/common/plugin_common_choose_project.h>
#include <ki_exception.h>
#include <string_utils.h>
#include <nlohmann/json.hpp>
#include <core/json_serializers.h>
#include <wx/log.h>
#include <wx/stream.h>
@ -61,6 +65,81 @@ LIB_ID EASYEDAPRO::ToKiCadLibID( const wxString& aLibName, const wxString& aLibR
}
std::vector<IMPORT_PROJECT_DESC>
EASYEDAPRO::ProjectToSelectorDialog( const nlohmann::json& aProject, bool aPcbOnly, bool aSchOnly )
{
std::vector<IMPORT_PROJECT_DESC> result;
std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics = aProject.at( "schematics" );
std::map<wxString, EASYEDAPRO::PRJ_BOARD> prjBoards = aProject.at( "boards" );
std::map<wxString, wxString> prjPcbNames = aProject.at( "pcbs" );
for( const auto& [prjName, board] : prjBoards )
{
IMPORT_PROJECT_DESC desc;
desc.ComboName = desc.ComboId = prjName;
desc.PCBId = board.pcb;
desc.SchematicId = board.schematic;
auto pcbNameIt = prjPcbNames.find( desc.PCBId );
if( pcbNameIt != prjPcbNames.end() )
{
desc.PCBName = pcbNameIt->second;
if( desc.PCBName.empty() )
desc.PCBName = pcbNameIt->first;
prjPcbNames.erase( pcbNameIt );
}
auto schIt = prjSchematics.find( desc.SchematicId );
if( schIt != prjSchematics.end() )
{
desc.SchematicName = schIt->second.name;
if( desc.SchematicName.empty() )
desc.SchematicName = schIt->first;
prjSchematics.erase( schIt );
}
result.emplace_back( desc );
}
if( !aSchOnly )
{
for( const auto& [pcbId, pcbName] : prjPcbNames )
{
IMPORT_PROJECT_DESC desc;
desc.PCBId = pcbId;
desc.PCBName = pcbName;
if( desc.PCBName.empty() )
desc.PCBName = pcbId;
result.emplace_back( desc );
}
}
if( !aPcbOnly )
{
for( const auto& [schId, schData] : prjSchematics )
{
IMPORT_PROJECT_DESC desc;
desc.SchematicId = schId;
desc.SchematicName = schData.name;
if( desc.SchematicName.empty() )
desc.SchematicName = schId;
result.emplace_back( desc );
}
}
return result;
}
nlohmann::json EASYEDAPRO::ReadProjectFile( const wxString& aZipFileName )
{
std::shared_ptr<wxZipEntry> entry;

View File

@ -30,6 +30,8 @@
#include <lib_id.h>
#include <nlohmann/json_fwd.hpp>
struct IMPORT_PROJECT_DESC;
#define EASY_IT_CONTINUE return false
#define EASY_IT_BREAK return true
@ -40,6 +42,10 @@ wxString ShortenLibName( wxString aProjectName );
LIB_ID ToKiCadLibID( const wxString& aLibName, const wxString& aLibReference );
std::vector<IMPORT_PROJECT_DESC> ProjectToSelectorDialog( const nlohmann::json& aProject,
bool aPcbOnly = false,
bool aSchOnly = false );
nlohmann::json ReadProjectFile( const wxString& aZipFileName );
void IterateZipFiles(

View File

@ -941,14 +941,22 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
case MAIL_IMPORT_FILE:
{
// Extract file format type and path (plugin type and path separated with \n)
size_t split = payload.find( '\n' );
wxCHECK( split != std::string::npos, /*void*/ );
// Extract file format type and path (plugin type, path and properties keys, values separated with \n)
std::stringstream ss( payload );
char delim = '\n';
std::string formatStr;
wxCHECK( std::getline( ss, formatStr, delim ), /* void */ );
std::string fnameStr;
wxCHECK( std::getline( ss, fnameStr, delim ), /* void */ );
wxASSERT( !fnameStr.empty() );
int importFormat;
try
{
importFormat = std::stoi( payload.substr( 0, split ) );
importFormat = std::stoi( formatStr );
}
catch( std::invalid_argument& )
{
@ -956,11 +964,23 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
importFormat = -1;
}
std::string path = payload.substr( split + 1 );
wxASSERT( !path.empty() );
STRING_UTF8_MAP props;
do
{
std::string key, value;
if( !std::getline( ss, key, delim ) )
break;
std::getline( ss, value, delim ); // We may want an empty string as value
props.emplace( key, value );
} while( true );
if( importFormat >= 0 )
importFile( path, importFormat );
importFile( fnameStr, importFormat, props.empty() ? nullptr : &props );
break;
}

View File

@ -30,6 +30,7 @@
#include <connection_graph.h>
#include <dialog_migrate_buses.h>
#include <dialog_symbol_remap.h>
#include <dialog_import_choose_project.h>
#include <eeschema_settings.h>
#include <id.h>
#include <kiface_base.h>
@ -41,6 +42,7 @@
#include <project_rescue.h>
#include <project_sch.h>
#include <dialog_HTML_reporter_base.h>
#include <plugins/common/plugin_common_choose_project.h>
#include <reporter.h>
#include <richio.h>
#include <sch_bus_entry.h>
@ -1282,7 +1284,8 @@ bool SCH_EDIT_FRAME::doAutoSave()
}
void SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
const STRING_UTF8_MAP* aProperties )
{
wxFileName filename( aFileName );
wxFileName newfilename;
@ -1299,7 +1302,7 @@ void SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
case SCH_IO_MGR::SCH_EASYEDAPRO:
{
// We insist on caller sending us an absolute path, if it does not, we say it's a bug.
wxCHECK_MSG( filename.IsAbsolute(), /*void*/,
wxCHECK_MSG( filename.IsAbsolute(), false,
wxS( "Import schematic: path is not absolute!" ) );
try
@ -1308,36 +1311,57 @@ void SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
DIALOG_HTML_REPORTER errorReporter( this );
WX_PROGRESS_REPORTER progressReporter( this, _( "Importing Schematic" ), 1 );
pi->SetReporter( errorReporter.m_Reporter );
pi->SetProgressReporter( &progressReporter );
Schematic().SetRoot( pi->LoadSchematicFile( aFileName, &Schematic() ) );
PROJECT_CHOOSER_PLUGIN* projectChooserPlugin =
dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( (SCH_PLUGIN*) pi );
if( errorReporter.m_Reporter->HasMessage() )
if( projectChooserPlugin )
{
errorReporter.m_Reporter->Flush(); // Build HTML messages
errorReporter.ShowModal();
projectChooserPlugin->RegisterChooseProjectCallback(
std::bind( DIALOG_IMPORT_CHOOSE_PROJECT::GetSelectionsModal, this,
std::placeholders::_1 ) );
}
// Non-KiCad schematics do not use a drawing-sheet (or if they do, it works differently
// to KiCad), so set it to an empty one
DS_DATA_MODEL& drawingSheet = DS_DATA_MODEL::GetTheInstance();
drawingSheet.SetEmptyLayout();
BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
pi->SetReporter( errorReporter.m_Reporter );
pi->SetProgressReporter( &progressReporter );
newfilename.SetPath( Prj().GetProjectPath() );
newfilename.SetName( Prj().GetProjectName() );
newfilename.SetExt( KiCadSchematicFileExtension );
SCH_SHEET* loadedSheet =
pi->LoadSchematicFile( aFileName, &Schematic(), nullptr, aProperties );
SetScreen( GetCurrentSheet().LastScreen() );
if( loadedSheet )
{
Schematic().SetRoot( loadedSheet );
Schematic().Root().SetFileName( newfilename.GetFullName() );
GetScreen()->SetFileName( newfilename.GetFullPath() );
GetScreen()->SetContentModified();
if( errorReporter.m_Reporter->HasMessage() )
{
errorReporter.m_Reporter->Flush(); // Build HTML messages
errorReporter.ShowModal();
}
RecalculateConnections( nullptr, GLOBAL_CLEANUP );
// Non-KiCad schematics do not use a drawing-sheet (or if they do, it works differently
// to KiCad), so set it to an empty one
DS_DATA_MODEL& drawingSheet = DS_DATA_MODEL::GetTheInstance();
drawingSheet.SetEmptyLayout();
BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
// Only perform the dangling end test on root sheet.
GetScreen()->TestDanglingEnds();
newfilename.SetPath( Prj().GetProjectPath() );
newfilename.SetName( Prj().GetProjectName() );
newfilename.SetExt( KiCadSchematicFileExtension );
SetScreen( GetCurrentSheet().LastScreen() );
Schematic().Root().SetFileName( newfilename.GetFullName() );
GetScreen()->SetFileName( newfilename.GetFullPath() );
GetScreen()->SetContentModified();
RecalculateConnections( nullptr, GLOBAL_CLEANUP );
// Only perform the dangling end test on root sheet.
GetScreen()->TestDanglingEnds();
}
else
{
CreateScreens();
}
}
catch( const IO_ERROR& ioe )
{
@ -1398,6 +1422,7 @@ void SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
break;
}
return true;
}

View File

@ -955,7 +955,8 @@ private:
* @param full filepath of file to be imported.
* @param aFileType SCH_FILE_T value for file type
*/
void importFile( const wxString& aFileName, int aFileType );
bool importFile( const wxString& aFileName, int aFileType,
const STRING_UTF8_MAP* aProperties = nullptr );
/**
* Save \a aSheet to a schematic file.

View File

@ -416,19 +416,27 @@ SCH_SHEET* SCH_EASYEDAPRO_PLUGIN::LoadSchematicFile( const wxString& aFileName,
nlohmann::json project = EASYEDAPRO::ReadProjectFile( aFileName );
std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics = project.at( "schematics" );
std::map<wxString, EASYEDAPRO::PRJ_BOARD> prjBoards = project.at( "boards" );
std::map<wxString, wxString> prjPcbNames = project.at( "pcbs" );
wxString schematicToLoad;
if( prjBoards.size() > 0 )
if( aProperties && aProperties->Exists( "sch_id" ) )
{
EASYEDAPRO::PRJ_BOARD boardToLoad = prjBoards.begin()->second;
schematicToLoad = boardToLoad.schematic;
schematicToLoad = aProperties->at( "sch_id" );
}
else if( prjSchematics.size() > 0 )
else
{
schematicToLoad = prjSchematics.begin()->first;
if( prjSchematics.size() == 1 )
{
schematicToLoad = prjSchematics.begin()->first;
}
else
{
std::vector<IMPORT_PROJECT_DESC> chosen = m_choose_project_handler(
EASYEDAPRO::ProjectToSelectorDialog( project, false, true ) );
if( chosen.size() > 0 )
schematicToLoad = chosen[0].SchematicId;
}
}
if( schematicToLoad.empty() )

View File

@ -27,13 +27,14 @@
#include <sch_io_mgr.h>
#include <reporter.h>
#include <plugins/common/plugin_common_choose_project.h>
class SCH_SHEET;
class SCH_SCREEN;
class SCH_EASYEDAPRO_PLUGIN : public SCH_PLUGIN
class SCH_EASYEDAPRO_PLUGIN : public SCH_PLUGIN, public PROJECT_CHOOSER_PLUGIN
{
public:
SCH_EASYEDAPRO_PLUGIN();

View File

@ -19,9 +19,6 @@
*/
#include "import_proj.h"
#include <kicad_manager_frame.h>
#include <kiway.h>
#include <kiway_player.h>
#include <wildcards_and_files_ext.h>
#include <macros.h>
#include <string_utils.h>
@ -29,6 +26,20 @@
#include <wx/msgdlg.h>
#include <kiway.h>
#include <kiway_player.h>
#include <kicad_manager_frame.h>
#include <pcb_edit_frame.h>
#include <sch_edit_frame.h>
#include <io_mgr.h>
#include <sch_io_mgr.h>
#include <plugins/easyedapro/easyedapro_import_utils.h>
#include <plugins/easyedapro/easyedapro_parser.h>
#include <plugins/common/plugin_common_choose_project.h>
#include <dialogs/dialog_import_choose_project.h>
IMPORT_PROJ_HELPER::IMPORT_PROJ_HELPER( KICAD_MANAGER_FRAME* aFrame,
const std::vector<wxString>& aSchFileExtensions,
@ -137,7 +148,13 @@ void IMPORT_PROJ_HELPER::ImportIndividualFile( KICAD_T aFT, int aImportedFileTyp
KIWAY_PLAYER* frame = m_frame->Kiway().Player( frame_type, true );
std::string packet = StrPrintf( "%d\n%s", aImportedFileType, TO_UTF8( appImportFile ) );
std::stringstream ss;
ss << aImportedFileType << '\n' << TO_UTF8( appImportFile );
for( const auto& [key, value] : m_properties )
ss << '\n' << key << '\n' << value;
std::string packet = ss.str();
frame->Kiway().ExpressMail( frame_type, MAIL_IMPORT_FILE, packet, m_frame );
if( !frame->IsShownOnScreen() )
@ -151,8 +168,52 @@ void IMPORT_PROJ_HELPER::ImportIndividualFile( KICAD_T aFT, int aImportedFileTyp
}
void IMPORT_PROJ_HELPER::EasyEDAProProjectHandler()
{
wxFileName fname = m_InputFile;
if( fname.GetExt() == wxS( "epro" ) || fname.GetExt() == wxS( "zip" ) )
{
nlohmann::json project = EASYEDAPRO::ReadProjectFile( fname.GetFullPath() );
std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics = project.at( "schematics" );
std::map<wxString, EASYEDAPRO::PRJ_BOARD> prjBoards = project.at( "boards" );
std::map<wxString, wxString> prjPcbNames = project.at( "pcbs" );
std::vector<IMPORT_PROJECT_DESC> toImport =
EASYEDAPRO::ProjectToSelectorDialog( project, false, false );
if( toImport.size() > 1 )
{
toImport = DIALOG_IMPORT_CHOOSE_PROJECT::GetSelectionsModal( m_frame, toImport );
}
if( toImport.size() == 1 )
{
const IMPORT_PROJECT_DESC& desc = toImport[0];
m_properties["pcb_id"] = desc.PCBId;
m_properties["sch_id"] = desc.SchematicId;
}
else
{
m_properties["pcb_id"] = "";
m_properties["sch_id"] = "";
}
}
}
void IMPORT_PROJ_HELPER::ImportFiles( int aImportedSchFileType, int aImportedPcbFileType )
{
m_properties.clear();
if( aImportedSchFileType == SCH_IO_MGR::SCH_EASYEDAPRO
|| aImportedPcbFileType == IO_MGR::EASYEDAPRO )
{
EasyEDAProProjectHandler();
}
ImportIndividualFile( SCHEMATIC_T, aImportedSchFileType );
ImportIndividualFile( PCB_T, aImportedPcbFileType );
}

View File

@ -3,6 +3,7 @@
#include <wx/filename.h>
#include <core/typeinfo.h>
#include <string_utf8_map.h>
class KICAD_MANAGER_FRAME;
@ -36,6 +37,8 @@ public:
private:
KICAD_MANAGER_FRAME* m_frame;
STRING_UTF8_MAP m_properties;
std::vector<wxString> m_copiedSchPaths;
std::vector<wxString> m_copiedPcbPaths;
@ -44,6 +47,8 @@ private:
void OutputCopyError( const wxFileName& aSrc, const wxFileName& aFileCopy );
void ImportIndividualFile( KICAD_T aKicad_T, int aImportedFileType );
void EasyEDAProProjectHandler();
};
#endif

View File

@ -49,6 +49,7 @@
#include <pcb_edit_frame.h>
#include <pcbnew_settings.h>
#include <render_settings.h>
#include <string_utf8_map.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_selection_tool.h>
@ -673,14 +674,22 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
case MAIL_IMPORT_FILE:
{
// Extract file format type and path (plugin type and path separated with \n)
size_t split = payload.find( '\n' );
wxCHECK( split != std::string::npos, /*void*/ );
// Extract file format type and path (plugin type, path and properties keys, values separated with \n)
std::stringstream ss( payload );
char delim = '\n';
std::string formatStr;
wxCHECK( std::getline( ss, formatStr, delim ), /* void */ );
std::string fnameStr;
wxCHECK( std::getline( ss, fnameStr, delim ), /* void */ );
wxASSERT( !fnameStr.empty() );
int importFormat;
try
{
importFormat = std::stoi( payload.substr( 0, split ) );
importFormat = std::stoi( formatStr );
}
catch( std::invalid_argument& )
{
@ -688,11 +697,23 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
importFormat = -1;
}
std::string path = payload.substr( split + 1 );
wxASSERT( !path.empty() );
STRING_UTF8_MAP props;
std::string key, value;
do
{
if( !std::getline( ss, key, delim ) )
break;
if( !std::getline( ss, value, delim ) )
break;
props.emplace( key, value );
} while( true );
if( importFormat >= 0 )
importFile( path, importFormat );
importFile( fnameStr, importFormat, props.empty() ? nullptr : &props );
break;
}

View File

@ -48,6 +48,7 @@
#include <widgets/wx_infobar.h>
#include <widgets/wx_progress_reporters.h>
#include <settings/settings_manager.h>
#include <string_utf8_map.h>
#include <paths.h>
#include <pgm_base.h>
#include <project/project_file.h>
@ -57,6 +58,8 @@
#include <plugins/cadstar/cadstar_pcb_archive_plugin.h>
#include <plugins/kicad/pcb_plugin.h>
#include <dialogs/dialog_imported_layers.h>
#include <dialogs/dialog_import_choose_project.h>
#include <plugins/common/plugin_common_choose_project.h>
#include <tools/pcb_actions.h>
#include "footprint_info_impl.h"
#include <board_commit.h>
@ -609,6 +612,16 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
std::bind( DIALOG_IMPORTED_LAYERS::GetMapModal, this, std::placeholders::_1 ) );
}
PROJECT_CHOOSER_PLUGIN* projectChooserPlugin =
dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( (PLUGIN*) pi );
if( projectChooserPlugin )
{
projectChooserPlugin->RegisterChooseProjectCallback(
std::bind( DIALOG_IMPORT_CHOOSE_PROJECT::GetSelectionsModal, this,
std::placeholders::_1 ) );
}
// This will rename the file if there is an autosave and the user want to recover
CheckForAutoSaveFile( fullFileName );
@ -624,6 +637,9 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
STRING_UTF8_MAP props;
if( m_importProperties )
props.insert( m_importProperties->begin(), m_importProperties->end() );
// EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
props["page_width"] = std::to_string( GetPageSizeIU().x );
props["page_height"] = std::to_string( GetPageSizeIU().y );
@ -1174,8 +1190,11 @@ bool PCB_EDIT_FRAME::doAutoSave()
}
bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
const STRING_UTF8_MAP* aProperties )
{
m_importProperties = aProperties;
switch( (IO_MGR::PCB_FILE_T) aFileType )
{
case IO_MGR::CADSTAR_PCB_ARCHIVE:
@ -1188,6 +1207,8 @@ bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
default: break;
}
m_importProperties = nullptr;
return false;
}

View File

@ -193,7 +193,8 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_inspectClearanceDlg( nullptr ),
m_inspectConstraintsDlg( nullptr ),
m_footprintDiffDlg( nullptr ),
m_netInspectorDlg( nullptr )
m_netInspectorDlg( nullptr ),
m_importProperties( nullptr )
{
m_maximizeByDefault = true;
m_showBorderAndTitleBlock = true; // true to display sheet references

View File

@ -57,6 +57,7 @@ class FP_LIB_TABLE;
class BOARD_NETLIST_UPDATER;
class ACTION_MENU;
class TOOL_ACTION;
class STRING_UTF8_MAP;
enum LAST_PATH_TYPE : unsigned int;
@ -506,17 +507,6 @@ public:
*/
void OnExportHyperlynx( wxCommandEvent& event );
/**
* run teardrop tool
*/
void OnRunTeardropTool( wxCommandEvent& event );
/**
* Remove all teardrops
*/
void OnRemoveTeardropTool( wxCommandEvent& event );
/**
* Create an IDF3 compliant BOARD (*.emn) and LIBRARY (*.emp) file.
*
@ -572,8 +562,6 @@ public:
bool resetTextEffects = true, bool resetFabricationAttrs = true,
bool reset3DModels = true, bool* aUpdated = nullptr );
bool FootprintMatchesLibrary();
/**
* Install the corresponding dialog editor for the given item.
*
@ -804,7 +792,8 @@ protected:
* @param full file path of file to be imported.
* @param aFileType PCB_FILE_T value for file type
*/
bool importFile( const wxString& aFileName, int aFileType );
bool importFile( const wxString& aFileName, int aFileType,
const STRING_UTF8_MAP* aProperties = nullptr );
bool canCloseWindow( wxCloseEvent& aCloseEvent ) override;
void doCloseWindow() override;
@ -859,6 +848,8 @@ private:
DIALOG_BOOK_REPORTER* m_footprintDiffDlg;
DIALOG_NET_INSPECTOR* m_netInspectorDlg;
const STRING_UTF8_MAP* m_importProperties; // Properties used for non-KiCad import.
/**
* Keep track of viewport so that track net labels can be adjusted when it changes.
*/

View File

@ -43,6 +43,7 @@
#include <nlohmann/json.hpp>
#include <core/json_serializers.h>
#include <core/map_helpers.h>
#include <string_utf8_map.h>
struct EASYEDAPRO_PLUGIN::PRJ_DATA
@ -125,23 +126,31 @@ BOARD* EASYEDAPRO_PLUGIN::LoadBoard( const wxString& aFileName, BOARD* aAppendTo
{
nlohmann::json project = EASYEDAPRO::ReadProjectFile( aFileName );
std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics = project.at( "schematics" );
std::map<wxString, EASYEDAPRO::PRJ_BOARD> prjBoards = project.at( "boards" );
std::map<wxString, wxString> prjPcbNames = project.at( "pcbs" );
wxString pcbToLoad;
if( prjBoards.size() > 0 )
if( m_props && m_props->Exists( "pcb_id" ) )
{
EASYEDAPRO::PRJ_BOARD boardToLoad = prjBoards.begin()->second;
pcbToLoad = boardToLoad.pcb;
pcbToLoad = m_props->at( "pcb_id" );
}
else if( prjPcbNames.size() > 0 )
else
{
pcbToLoad = prjPcbNames.begin()->first;
std::map<wxString, wxString> prjPcbNames = project.at( "pcbs" );
if( prjPcbNames.size() == 1 )
{
pcbToLoad = prjPcbNames.begin()->first;
}
else
{
std::vector<IMPORT_PROJECT_DESC> chosen = m_choose_project_handler(
EASYEDAPRO::ProjectToSelectorDialog( project, true, false ) );
if( chosen.size() > 0 )
pcbToLoad = chosen[0].PCBId;
}
}
if( prjPcbNames.empty() )
if( pcbToLoad.empty() )
return nullptr;
LoadAllDataFromProject( aFileName, project );

View File

@ -27,9 +27,10 @@
#include <io_mgr.h>
#include <nlohmann/json_fwd.hpp>
#include <plugins/common/plugin_common_choose_project.h>
class EASYEDAPRO_PLUGIN : public PLUGIN
class EASYEDAPRO_PLUGIN : public PLUGIN, public PROJECT_CHOOSER_PLUGIN
{
public:
const wxString PluginName() const override