Added a new plugin that can save and load to clipboard, using ctrl+shift+c/v for copy pasting

Added the needed kicad_clipboard files and made copy pasted modules have no path
This commit is contained in:
Kristoffer Ödmark 2017-04-15 18:08:23 +02:00 committed by Tomasz Włostowski
parent 6573a43f3a
commit c0981b8444
12 changed files with 360 additions and 9 deletions

View File

@ -403,6 +403,7 @@ set( PCB_COMMON_SRCS
../pcbnew/eagle_plugin.cpp
../pcbnew/legacy_plugin.cpp
../pcbnew/kicad_plugin.cpp
../pcbnew/kicad_clipboard.cpp
../pcbnew/gpcb_plugin.cpp
../pcbnew/pcb_netlist.cpp
widgets/widget_net_selector.cpp

199
pcbnew/kicad_clipboard.cpp Normal file
View File

@ -0,0 +1,199 @@
/**
* @file kicad_clipboard.cpp
* @brief Kicad clipboard plugin that piggybacks on the kicad_plugin
*
* @author Kristoffer Ödmark
* @version 1.0
* @date 2017-05-03
*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see CHANGELOG.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 2
* 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/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wx/clipbrd.h>
#include <common.h>
#include <pcb_parser.h>
#include <class_netinfo.h>
#include <class_board.h>
#include <build_version.h>
#include <kicad_plugin.h>
#include <kicad_clipboard.h>
CLIPBOARD_IO::CLIPBOARD_IO():
PCB_IO(),
m_formatter(),
m_parser( new CLIPBOARD_PARSER() )
{
m_out = &m_formatter;
}
CLIPBOARD_IO::~CLIPBOARD_IO(){}
STRING_FORMATTER* CLIPBOARD_IO::GetFormatter()
{
return &m_formatter;
}
void CLIPBOARD_IO::setBoard(BOARD* aBoard)
{
m_board = aBoard;
}
void CLIPBOARD_IO::writeHeader(BOARD* aBoard)
{
formatHeader( aBoard );
}
void CLIPBOARD_IO::SaveSelection( SELECTION& aSelected )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
// Prepare net mapping that assures that net codes saved in a file are consecutive integers
m_mapping->SetBoard( m_board );
// we will fake being a .kicad_pcb to get the full parser kicking
// This means we also need layers and nets
m_formatter.Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION,
m_formatter.Quotew( GetBuildVersion() ).c_str() );
if( aSelected.Empty() )
return;
writeHeader( m_board );
m_formatter.Print( 0, "\n" );
for( auto i : aSelected )
{
// Dont format stuff that cannot exist standalone!
if( ( i->Type() != PCB_MODULE_EDGE_T ) &&
( i->Type() != PCB_MODULE_TEXT_T ) &&
( i->Type() != PCB_PAD_T ) )
{
//std::cout <<"type "<< i->Type() << std::endl;
auto item = static_cast<BOARD_ITEM*>( i );
Format( item, 1 );
}
}
m_formatter.Print( 0, "\n)" );
if( wxTheClipboard->Open() )
{
wxTheClipboard->SetData( new wxTextDataObject( wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
wxTheClipboard->Close();
}
}
void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard,
const PROPERTIES* aProperties )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
init( aProperties );
m_board = aBoard; // after init()
// Prepare net mapping that assures that net codes saved in a file are consecutive integers
m_mapping->SetBoard( aBoard );
STRING_FORMATTER formatter;
m_out = &formatter;
m_out->Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION,
formatter.Quotew( GetBuildVersion() ).c_str() );
Format( aBoard, 1 );
m_out->Print( 0, ")\n" );
if( wxTheClipboard->Open() )
{
wxTheClipboard->SetData( new wxTextDataObject( wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
wxTheClipboard->Close();
}
}
BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
{
std::string result;
if( wxTheClipboard->Open() )
{
if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
{
wxTextDataObject data;
wxTheClipboard->GetData( data );
result = data.GetText().mb_str();
}
wxTheClipboard->Close();
}
STRING_LINE_READER reader(result, wxT( "clipboard" ) );
init( aProperties );
m_parser->SetLineReader( &reader );
m_parser->SetBoard( aAppendToMe );
BOARD* board;
try
{
board = dynamic_cast<BOARD*>( m_parser->Parse() );
}
catch( const FUTURE_FORMAT_ERROR& )
{
// Don't wrap a FUTURE_FORMAT_ERROR in another
throw;
}
catch( const PARSE_ERROR& parse_error )
{
if( m_parser->IsTooRecent() )
throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
else
throw;
}
if( !board )
{
// The parser loaded something that was valid, but wasn't a board.
THROW_PARSE_ERROR( _( "Clipboard content is not Kicad compatible" ),
m_parser->CurSource(), m_parser->CurLine(),
m_parser->CurLineNumber(), m_parser->CurOffset() );
}
// Give the filename to the board if it's new
if( !aAppendToMe )
board->SetFileName( aFileName );
return board;
}

81
pcbnew/kicad_clipboard.h Normal file
View File

@ -0,0 +1,81 @@
/**
* @file kicad_clipboard.h
* @brief
* @author Kristoffer Ödmark
* @version 1.0
* @date 2017-05-03
*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see CHANGELOG.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 2
* 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/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef KICAD_CLIPBOARD_H
#define KICAD_CLIPBOARD_H
#include <kicad_plugin.h>
#include <class_board_item.h>
#include <class_module.h>
#include <pcb_parser.h>
#include <memory.h>
#include <tool/selection.h>
class CLIPBOARD_PARSER : public PCB_PARSER
{
public:
CLIPBOARD_PARSER( LINE_READER* aReader = NULL ): PCB_PARSER( aReader ) {};
MODULE* parseMODULE( wxArrayString* aInitialComments )
throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR ) override
{
MODULE* mod = PCB_PARSER::parseMODULE(aInitialComments);
mod->SetPath( wxT( "" ) );
return mod;
}
};
class CLIPBOARD_IO : public PCB_IO
{
STRING_FORMATTER m_formatter;
CLIPBOARD_PARSER* m_parser;
public:
/* Saves the entire board to the clipboard formatted using the PCB_IO formatting */
void Save( const wxString& aFileName, BOARD* aBoard,
const PROPERTIES* aProperties = NULL ) override;
/* Writes all the settings of the BOARD* set by setBoard() and then adds all
* the BOARD_ITEM* found in selection formatted by PCB_IO to clipboard as a text
*/
void SaveSelection( SELECTION& selected );
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL ) override;
CLIPBOARD_IO();
~CLIPBOARD_IO();
void setBoard(BOARD* aBoard);
void writeHeader(BOARD* aBoard);
STRING_FORMATTER* GetFormatter();
};
#endif /* KICAD_CLIPBOARD_H */

View File

@ -527,9 +527,9 @@ void PCB_IO::formatLayer( const BOARD_ITEM* aItem ) const
m_out->Print( 0, " (layer %s)", m_out->Quotew( aItem->GetLayerName() ).c_str() );
}
void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
void PCB_IO::formatHeader( BOARD* aBoard, int aNestLevel ) const throw(IO_ERROR)
{
const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
m_out->Print( 0, "\n" );
@ -745,6 +745,12 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
filterNetClass( *aBoard, netclass ); // Remove empty nets (from a copy of a netclass)
netclass.Format( m_out, aNestLevel, m_ctl );
}
}
void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
throw( IO_ERROR )
{
formatHeader( aBoard );
// Save the modules.
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )

View File

@ -109,7 +109,7 @@ public:
return wxT( "kicad_pcb" );
}
void Save( const wxString& aFileName, BOARD* aBoard,
virtual void Save( const wxString& aFileName, BOARD* aBoard,
const PROPERTIES* aProperties = NULL ) override;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe,
@ -188,6 +188,10 @@ protected:
void init( const PROPERTIES* aProperties );
/// writes everything that comes before the board_items, like settings and layers etc
void formatHeader( BOARD* aBoard, int aNestLevel = 0 ) const
throw( IO_ERROR );
private:
void format( BOARD* aBoard, int aNestLevel = 0 ) const;

View File

@ -117,7 +117,6 @@ class PCB_PARSER : public PCB_LEXER
DRAWSEGMENT* parseDRAWSEGMENT();
TEXTE_PCB* parseTEXTE_PCB();
DIMENSION* parseDIMENSION();
/**
* Function parseMODULE
* @param aInitialComments may be a pointer to a heap allocated initial comment block
@ -327,4 +326,5 @@ public:
};
#endif // _PCBNEW_PARSER_H_

View File

@ -82,6 +82,9 @@ public:
/// Filters the items in the current selection (invokes dialog)
static TOOL_ACTION filterSelection;
/// Copy selected items to clipboard
static TOOL_ACTION selectionToClipboard;
// Edit Tool
/// Activation of the edit tool
static TOOL_ACTION editActivate;
@ -365,6 +368,7 @@ public:
static TOOL_ACTION drillOrigin;
static TOOL_ACTION crossProbeSchToPcb;
static TOOL_ACTION appendBoard;
static TOOL_ACTION appendClipboard;
static TOOL_ACTION showHelp;
static TOOL_ACTION showLocalRatsnest;
static TOOL_ACTION toBeDone;

View File

@ -142,6 +142,10 @@ TOOL_ACTION PCB_ACTIONS::appendBoard( "pcbnew.EditorControl.appendBoard",
AS_GLOBAL, 0,
"", "" );
TOOL_ACTION PCB_ACTIONS::appendClipboard( "pcbnew.EditorControl.appendClipboard",
AS_GLOBAL, MD_CTRL + MD_SHIFT + int( 'V' ),
"", "" );
TOOL_ACTION PCB_ACTIONS::highlightNet( "pcbnew.EditorControl.highlightNet",
AS_GLOBAL, 0,
"", "" );

View File

@ -40,6 +40,8 @@
#include <hotkeys.h>
#include <properties.h>
#include <io_mgr.h>
#include <kicad_plugin.h>
#include <kicad_clipboard.h>
#include <pcbnew_id.h>
#include <wxPcbStruct.h>
@ -727,9 +729,14 @@ int PCBNEW_CONTROL::DeleteItemCursor( const TOOL_EVENT& aEvent )
return 0;
}
int PCBNEW_CONTROL::AppendBoardFromClipboard( const TOOL_EVENT& aEvent )
{
CLIPBOARD_IO pi;
wxString noString("");
return AppendBoard( pi, noString );
}
int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent )
int PCBNEW_CONTROL::AppendBoardFromFile( const TOOL_EVENT& aEvent )
{
int open_ctl;
wxString fileName;
@ -746,6 +753,13 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent )
IO_MGR::PCB_FILE_T pluginType = plugin_type( fileName, open_ctl );
PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
return AppendBoard( *pi, fileName );
}
int PCBNEW_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName )
{
PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
// Mark existing tracks, in order to know what are the new tracks
// Tracks are inserted, not appended, so mark existing tracks to be
// able to select the new tracks only later
@ -778,7 +792,7 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent )
props["page_height"] = ybuf;
editFrame->GetDesignSettings().m_NetClasses.Clear();
pi->Load( fileName, board, &props );
pi.Load( fileName, board, &props );
}
catch( const IO_ERROR& ioe )
{
@ -945,9 +959,13 @@ void PCBNEW_CONTROL::setTransitions()
Go( &PCBNEW_CONTROL::SwitchCursor, PCB_ACTIONS::switchCursor.MakeEvent() );
Go( &PCBNEW_CONTROL::SwitchUnits, PCB_ACTIONS::switchUnits.MakeEvent() );
Go( &PCBNEW_CONTROL::DeleteItemCursor, PCB_ACTIONS::deleteItemCursor.MakeEvent() );
Go( &PCBNEW_CONTROL::AppendBoard, PCB_ACTIONS::appendBoard.MakeEvent() );
Go( &PCBNEW_CONTROL::ShowHelp, PCB_ACTIONS::showHelp.MakeEvent() );
Go( &PCBNEW_CONTROL::ToBeDone, PCB_ACTIONS::toBeDone.MakeEvent() );
// Append control
Go( &PCBNEW_CONTROL::AppendBoardFromFile,PCB_ACTIONS::appendBoard.MakeEvent() );
Go( &PCBNEW_CONTROL::AppendBoardFromClipboard
,PCB_ACTIONS::appendClipboard.MakeEvent() );
}

View File

@ -26,6 +26,7 @@
#define PCBNEW_CONTROL_H
#include <tool/tool_interactive.h>
#include <io_mgr.h>
#include <memory>
namespace KIGFX {
@ -79,7 +80,9 @@ public:
int SwitchCursor( const TOOL_EVENT& aEvent );
int SwitchUnits( const TOOL_EVENT& aEvent );
int DeleteItemCursor( const TOOL_EVENT& aEvent );
int AppendBoard( const TOOL_EVENT& aEvent );
int AppendBoardFromClipboard( const TOOL_EVENT& aEvent );
int AppendBoardFromFile( const TOOL_EVENT& aEvent );
int AppendBoard( PLUGIN& pi, wxString& fileName );
int ShowHelp( const TOOL_EVENT& aEvent );
int ToBeDone( const TOOL_EVENT& aEvent );

View File

@ -58,6 +58,9 @@ using namespace std::placeholders;
#include "pcb_bright_box.h"
#include "pcb_actions.h"
#include "kicad_plugin.h"
#include "kicad_clipboard.h"
// Selection tool actions
TOOL_ACTION PCB_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection",
AS_GLOBAL, 0,
@ -120,6 +123,11 @@ TOOL_ACTION PCB_ACTIONS::filterSelection( "pcbnew.InteractiveSelection.FilterSel
_( "Filter Selection" ), _( "Filter the types of items in the selection" ),
nullptr );
TOOL_ACTION PCB_ACTIONS::selectionToClipboard( "pcbnew.InteractiveSelection.CopyToClipboard",
AS_GLOBAL, MD_CTRL + MD_SHIFT + int( 'C' ),
_( "Copy to Clipboard" ), _( "Copy selected content to clipboard" ),
nullptr );
class SELECT_MENU: public CONTEXT_MENU
@ -609,11 +617,26 @@ void SELECTION_TOOL::setTransitions()
Go( &SELECTION_TOOL::selectCopper, PCB_ACTIONS::selectCopper.MakeEvent() );
Go( &SELECTION_TOOL::selectNet, PCB_ACTIONS::selectNet.MakeEvent() );
Go( &SELECTION_TOOL::selectSameSheet, PCB_ACTIONS::selectSameSheet.MakeEvent() );
Go( &SELECTION_TOOL::selectionToClipboard, PCB_ACTIONS::selectionToClipboard.MakeEvent() );
Go( &SELECTION_TOOL::selectOnSheetFromEeschema, PCB_ACTIONS::selectOnSheetFromEeschema.MakeEvent() );
Go( &SELECTION_TOOL::updateSelection, PCB_ACTIONS::selectionModified.MakeEvent() );
}
int SELECTION_TOOL::selectionToClipboard( const TOOL_EVENT& aEvent )
{
CLIPBOARD_IO io;
BOARD* board = getModel<BOARD>();
io.setBoard( board );
auto& selection = RequestSelection( SELECTION_DELETABLE | SELECTION_SANITIZE_PADS );
io.SaveSelection( selection );
return 0;
}
SELECTION_LOCK_FLAGS SELECTION_TOOL::CheckLock()
{
if( !m_locked || m_editModules )

View File

@ -299,6 +299,14 @@ private:
*/
void unselectVisually( BOARD_ITEM* aItem );
/**
* Function selectionToClipboard()
* Sends the current selection to the clipboard by formatting it as a fake pcb
* see AppendBoardFromClipboard for importing
* @return True if it was sent succesfully
*/
int selectionToClipboard( const TOOL_EVENT& aEvent );
/**
* Function selectionContains()
* Checks if the given point is placed within any of selected items' bounding box.