summaryrefslogtreecommitdiff
path: root/eeschema/dialogs/dialog_erc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'eeschema/dialogs/dialog_erc.cpp')
-rw-r--r--eeschema/dialogs/dialog_erc.cpp579
1 files changed, 579 insertions, 0 deletions
diff --git a/eeschema/dialogs/dialog_erc.cpp b/eeschema/dialogs/dialog_erc.cpp
new file mode 100644
index 0000000..f1f28c0
--- /dev/null
+++ b/eeschema/dialogs/dialog_erc.cpp
@@ -0,0 +1,579 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
+ * Copyright (C) 1992-2015 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 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
+ */
+
+/**
+ * @file dialog_erc.cpp
+ * @brief Electrical Rules Check dialog implementation.
+ */
+
+#include <fctsys.h>
+#include <class_drawpanel.h>
+#include <kicad_string.h>
+#include <gestfich.h>
+#include <pgm_base.h>
+#include <class_sch_screen.h>
+#include <schframe.h>
+#include <invoke_sch_dialog.h>
+#include <project.h>
+
+#include <netlist.h>
+#include <class_netlist_object.h>
+#include <sch_marker.h>
+#include <sch_sheet.h>
+#include <lib_pin.h>
+
+#include <dialog_erc.h>
+#include <erc.h>
+#include <id.h>
+
+
+bool DIALOG_ERC::m_writeErcFile = false;
+
+
+BEGIN_EVENT_TABLE( DIALOG_ERC, DIALOG_ERC_BASE )
+ EVT_COMMAND_RANGE( ID_MATRIX_0, ID_MATRIX_0 + ( PIN_NMAX * PIN_NMAX ) - 1,
+ wxEVT_COMMAND_BUTTON_CLICKED, DIALOG_ERC::ChangeErrorLevel )
+END_EVENT_TABLE()
+
+
+DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
+ DIALOG_ERC_BASE( parent, ID_DIALOG_ERC // parent looks for this ID explicitly
+ )
+{
+ m_parent = parent;
+ m_lastMarkerFound = NULL;
+ Init();
+
+ FixOSXCancelButtonIssue();
+
+ // Now all widgets have the size fixed, call FinishDialogSettings
+ FinishDialogSettings();
+}
+
+DIALOG_ERC::~DIALOG_ERC()
+{
+}
+
+
+void DIALOG_ERC::Init()
+{
+ m_initialized = false;
+
+ for( int ii = 0; ii < PIN_NMAX; ii++ )
+ {
+ for( int jj = 0; jj < PIN_NMAX; jj++ )
+ m_buttonList[ii][jj] = NULL;
+ }
+
+ m_WriteResultOpt->SetValue( m_writeErcFile );
+
+ SCH_SCREENS screens;
+ updateMarkerCounts( &screens );
+
+ DisplayERC_MarkersList();
+
+ // Init Panel Matrix
+ ReBuildMatrixPanel();
+
+ // Set the run ERC button as the default button.
+ m_buttonERC->SetDefault();
+}
+
+
+void DIALOG_ERC::updateMarkerCounts( SCH_SCREENS *screens )
+{
+ int markers = screens->GetMarkerCount( MARKER_BASE::MARKER_ERC,
+ MARKER_BASE::MARKER_SEVERITY_UNSPEC );
+ int warnings = screens->GetMarkerCount( MARKER_BASE::MARKER_ERC,
+ MARKER_BASE::MARKER_SEVERITY_WARNING );
+ int errors = screens->GetMarkerCount( MARKER_BASE::MARKER_ERC,
+ MARKER_BASE::MARKER_SEVERITY_ERROR );
+
+ wxString num;
+ num.Printf( wxT( "%d" ), markers );
+ m_TotalErrCount->SetValue( num );
+
+ num.Printf( wxT( "%d" ), errors );
+ m_LastErrCount->SetValue( num );
+
+ num.Printf( wxT( "%d" ), warnings );
+ m_LastWarningCount->SetValue( num );
+}
+
+
+/* Delete the old ERC markers, over the whole hierarchy
+ */
+void DIALOG_ERC::OnEraseDrcMarkersClick( wxCommandEvent& event )
+{
+ SCH_SCREENS ScreenList;
+
+ ScreenList.DeleteAllMarkers( MARKER_BASE::MARKER_ERC );
+ updateMarkerCounts( &ScreenList );
+
+ m_MarkersList->ClearList();
+ m_parent->GetCanvas()->Refresh();
+}
+
+
+
+/* event handler for Close button
+*/
+void DIALOG_ERC::OnButtonCloseClick( wxCommandEvent& event )
+{
+ Close();
+}
+
+void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& event )
+{
+ Destroy();
+}
+
+
+void DIALOG_ERC::OnResetMatrixClick( wxCommandEvent& event )
+{
+ ResetDefaultERCDiag( event );
+}
+
+
+void DIALOG_ERC::OnErcCmpClick( wxCommandEvent& event )
+{
+ wxBusyCursor();
+ m_MarkersList->ClearList();
+
+ m_MessagesList->Clear();
+ wxSafeYield(); // m_MarkersList must be redraw
+ wxArrayString messageList;
+ TestErc( &messageList );
+
+ for( unsigned ii = 0; ii < messageList.GetCount(); ii++ )
+ m_MessagesList->AppendText( messageList[ii] );
+}
+
+
+void DIALOG_ERC::OnLeftClickMarkersList( wxHtmlLinkEvent& event )
+{
+ wxString link = event.GetLinkInfo().GetHref();
+
+ m_lastMarkerFound = NULL;
+
+ long index;
+
+ if( !link.ToLong( &index ) )
+ return;
+
+ const SCH_MARKER* marker = m_MarkersList->GetItem( index );
+
+ if( marker == NULL )
+ return;
+
+ // Search for the selected marker
+ SCH_SHEET_PATH* sheet;
+ SCH_SHEET_LIST SheetList;
+ bool notFound = true;
+
+ for( sheet = SheetList.GetFirst(); sheet; sheet = SheetList.GetNext() )
+ {
+ SCH_ITEM* item = (SCH_ITEM*) sheet->LastDrawList();
+
+ for( ; item; item = item->Next() )
+ {
+ if( item == marker )
+ {
+ notFound = false;
+ break;
+ }
+ }
+
+ if( notFound == false )
+ break;
+ }
+
+ if( notFound ) // Error
+ {
+ wxMessageBox( _( "Marker not found" ) );
+
+ // The marker was deleted, so rebuild marker list
+ DisplayERC_MarkersList();
+ return;
+ }
+
+ if( *sheet != m_parent->GetCurrentSheet() )
+ {
+ sheet->LastScreen()->SetZoom( m_parent->GetScreen()->GetZoom() );
+ m_parent->SetCurrentSheet( *sheet );
+ m_parent->GetCurrentSheet().UpdateAllScreenReferences();
+ }
+
+ m_lastMarkerFound = marker;
+ m_parent->SetCrossHairPosition( marker->m_Pos );
+ m_parent->RedrawScreen( marker->m_Pos, false);
+}
+
+
+void DIALOG_ERC::OnLeftDblClickMarkersList( wxMouseEvent& event )
+{
+ // Remember: OnLeftClickMarkersList was called just berfore
+ // and therefore m_lastMarkerFound was initialized.
+ // (NULL if not found)
+ if( m_lastMarkerFound )
+ {
+ m_parent->SetCrossHairPosition( m_lastMarkerFound->m_Pos );
+ m_parent->RedrawScreen( m_lastMarkerFound->m_Pos, true );
+ // prevent a mouse left button release event in
+ // coming from the ERC dialog double click
+ // ( the button is released after closing this dialog and will generate
+ // an unwanted event in parent frame)
+ m_parent->SkipNextLeftButtonReleaseEvent();
+ }
+
+ Close();
+}
+
+
+void DIALOG_ERC::ReBuildMatrixPanel()
+{
+ // Try to know the size of bitmap button used in drc matrix
+ wxBitmapButton * dummy = new wxBitmapButton( m_matrixPanel, wxID_ANY, KiBitmap( ercerr_xpm ) );
+ wxSize bitmap_size = dummy->GetSize();
+ delete dummy;
+
+ if( !DiagErcTableInit )
+ {
+ memcpy( DiagErc, DefaultDiagErc, sizeof(DefaultDiagErc) );
+ DiagErcTableInit = true;
+ }
+
+ wxPoint pos;
+ // Get the current text size:use a dummy text.
+ wxStaticText* text = new wxStaticText( m_matrixPanel, -1, wxT( "W" ), pos );
+ int text_height = text->GetRect().GetHeight();
+ bitmap_size.y = std::max( bitmap_size.y, text_height );
+ delete text;
+
+ // compute the Y pos interval:
+ pos.y = text_height;
+
+ if( m_initialized == false )
+ {
+ // Print row labels
+ for( int ii = 0; ii < PIN_NMAX; ii++ )
+ {
+ int y = pos.y + (ii * bitmap_size.y);
+ text = new wxStaticText( m_matrixPanel, -1, CommentERC_H[ii],
+ wxPoint( 5, y + ( bitmap_size.y / 2) - (text_height / 2) ) );
+
+ int x = text->GetRect().GetRight();
+ pos.x = std::max( pos.x, x );
+ }
+
+ pos.x += 5;
+ }
+ else
+ pos = m_buttonList[0][0]->GetPosition();
+
+ for( int ii = 0; ii < PIN_NMAX; ii++ )
+ {
+ int y = pos.y + (ii * bitmap_size.y);
+
+ for( int jj = 0; jj <= ii; jj++ )
+ {
+ // Add column labels (only once)
+ int diag = DiagErc[ii][jj];
+ int x = pos.x + (jj * bitmap_size.x);
+
+ if( (ii == jj) && !m_initialized )
+ {
+ wxPoint txtpos;
+ txtpos.x = x + (bitmap_size.x / 2);
+ txtpos.y = y - text_height;
+ text = new wxStaticText( m_matrixPanel, -1, CommentERC_V[ii], txtpos );
+ }
+
+ int event_id = ID_MATRIX_0 + ii + ( jj * PIN_NMAX );
+ BITMAP_DEF bitmap_butt = erc_green_xpm;
+
+ delete m_buttonList[ii][jj];
+ m_buttonList[ii][jj] = new wxBitmapButton( m_matrixPanel,
+ event_id,
+ KiBitmap( bitmap_butt ),
+ wxPoint( x, y ) );
+ setDRCMatrixButtonState( m_buttonList[ii][jj], diag );
+ }
+ }
+
+ m_initialized = true;
+}
+
+
+void DIALOG_ERC::setDRCMatrixButtonState( wxBitmapButton *aButton, int aState )
+{
+ BITMAP_DEF bitmap_butt = NULL;
+ wxString tooltip;
+
+ switch( aState )
+ {
+ case OK:
+ bitmap_butt = erc_green_xpm;
+ tooltip = _( "No error or warning" );
+ break;
+
+ case WAR:
+ bitmap_butt = ercwarn_xpm;
+ tooltip = _( "Generate warning" );
+ break;
+
+ case ERR:
+ bitmap_butt = ercerr_xpm;
+ tooltip = _( "Generate error" );
+ break;
+ }
+
+ if( bitmap_butt )
+ {
+ aButton->SetBitmap( KiBitmap( bitmap_butt ) );
+ aButton->SetToolTip( tooltip );
+ }
+}
+
+
+void DIALOG_ERC::DisplayERC_MarkersList()
+{
+ SCH_SHEET_LIST sheetList;
+ m_MarkersList->ClearList();
+
+ SCH_SHEET_PATH* sheet = sheetList.GetFirst();
+
+ for( ; sheet != NULL; sheet = sheetList.GetNext() )
+ {
+ SCH_ITEM* item = sheet->LastDrawList();
+
+ for( ; item != NULL; item = item->Next() )
+ {
+ if( item->Type() != SCH_MARKER_T )
+ continue;
+
+ SCH_MARKER* marker = (SCH_MARKER*) item;
+
+ if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC )
+ continue;
+
+ m_MarkersList->AppendToList( marker );
+ }
+ }
+
+ m_MarkersList->DisplayList();
+}
+
+
+void DIALOG_ERC::ResetDefaultERCDiag( wxCommandEvent& event )
+{
+ memcpy( DiagErc, DefaultDiagErc, sizeof( DiagErc ) );
+ ReBuildMatrixPanel();
+}
+
+
+void DIALOG_ERC::ChangeErrorLevel( wxCommandEvent& event )
+{
+ int id, level, ii, x, y;
+ wxPoint pos;
+
+ id = event.GetId();
+ ii = id - ID_MATRIX_0;
+ wxBitmapButton* butt = (wxBitmapButton*) event.GetEventObject();
+ pos = butt->GetPosition();
+
+ x = ii / PIN_NMAX; y = ii % PIN_NMAX;
+
+ level = DiagErc[y][x];
+
+ //change to the next error level
+ switch( level )
+ {
+ case OK:
+ level = WAR;
+ break;
+
+ case WAR:
+ level = ERR;
+ break;
+
+ case ERR:
+ level = OK;
+ break;
+ }
+
+ setDRCMatrixButtonState( butt, level);
+
+ DiagErc[y][x] = DiagErc[x][y] = level;
+}
+
+
+void DIALOG_ERC::TestErc( wxArrayString* aMessagesList )
+{
+ wxFileName fn;
+
+ if( !DiagErcTableInit )
+ {
+ memcpy( DiagErc, DefaultDiagErc, sizeof( DefaultDiagErc ) );
+ DiagErcTableInit = true;
+ }
+
+ m_writeErcFile = m_WriteResultOpt->GetValue();
+
+ // Build the whole sheet list in hierarchy (sheet, not screen)
+ SCH_SHEET_LIST sheets;
+ sheets.AnnotatePowerSymbols( Prj().SchLibs() );
+
+ if( m_parent->CheckAnnotate( aMessagesList, false ) )
+ {
+ if( aMessagesList )
+ {
+ wxString msg = _( "Annotation required!" );
+ msg += wxT( "\n" );
+ aMessagesList->Add( msg );
+ }
+
+ return;
+ }
+
+ SCH_SCREENS screens;
+
+ // Erase all previous DRC markers.
+ screens.DeleteAllMarkers( MARKER_BASE::MARKER_ERC );
+
+ for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() )
+ {
+ /* Ff wire list has changed, delete Undo Redo list to avoid pointers on deleted
+ * data problems.
+ */
+ if( screen->SchematicCleanUp( NULL ) )
+ screen->ClearUndoRedoList();
+ }
+
+ /* Test duplicate sheet names inside a given sheet, one cannot have sheets with
+ * duplicate names (file names can be duplicated).
+ */
+ TestDuplicateSheetNames( true );
+
+ std::auto_ptr<NETLIST_OBJECT_LIST> objectsConnectedList( m_parent->BuildNetListBase() );
+
+ // Reset the connection type indicator
+ objectsConnectedList->ResetConnectionsType();
+
+ unsigned lastNet;
+ unsigned nextNet = lastNet = 0;
+ int MinConn = NOC;
+
+ for( unsigned net = 0; net < objectsConnectedList->size(); net++ )
+ {
+ if( objectsConnectedList->GetItemNet( lastNet ) !=
+ objectsConnectedList->GetItemNet( net ) )
+ {
+ // New net found:
+ MinConn = NOC;
+ nextNet = net;
+ }
+
+ switch( objectsConnectedList->GetItemType( net ) )
+ {
+ // These items do not create erc problems
+ case NET_ITEM_UNSPECIFIED:
+ case NET_SEGMENT:
+ case NET_BUS:
+ case NET_JUNCTION:
+ case NET_LABEL:
+ case NET_BUSLABELMEMBER:
+ case NET_PINLABEL:
+ case NET_GLOBBUSLABELMEMBER:
+ break;
+
+ case NET_HIERLABEL:
+ case NET_HIERBUSLABELMEMBER:
+ case NET_SHEETLABEL:
+ case NET_SHEETBUSLABELMEMBER:
+ case NET_GLOBLABEL:
+
+ // ERC problems when pin sheets do not match hierarchical labels.
+ // Each pin sheet must match a hierarchical label
+ // Each hierarchical label must match a pin sheet
+ TestLabel( objectsConnectedList.get(), net, nextNet );
+ break;
+
+ case NET_NOCONNECT:
+
+ // ERC problems when a noconnect symbol is connected to more than one pin.
+ MinConn = NET_NC;
+
+ if( CountPinsInNet( objectsConnectedList.get(), nextNet ) > 1 )
+ Diagnose( objectsConnectedList->GetItem( net ), NULL, MinConn, UNC );
+
+ break;
+
+ case NET_PIN:
+
+ // Look for ERC problems between pins:
+ TestOthersItems( objectsConnectedList.get(), net, nextNet, &MinConn );
+ break;
+ }
+
+ lastNet = net;
+ }
+
+ // Displays global results:
+ updateMarkerCounts( &screens );
+
+ // Display diags:
+ DisplayERC_MarkersList();
+
+ // Display new markers:
+ m_parent->GetCanvas()->Refresh();
+
+ if( m_writeErcFile )
+ {
+ fn = g_RootSheet->GetScreen()->GetFileName();
+ fn.SetExt( wxT( "erc" ) );
+
+ wxFileDialog dlg( this, _( "ERC File" ), fn.GetPath(), fn.GetFullName(),
+ _( "Electronic rule check file (.erc)|*.erc" ),
+ wxFD_SAVE );
+
+ if( dlg.ShowModal() == wxID_CANCEL )
+ return;
+
+ if( WriteDiagnosticERC( dlg.GetPath() ) )
+ ExecuteFile( this, Pgm().GetEditorName(), QuoteFullPath( fn ) );
+ }
+}
+
+
+wxDialog* InvokeDialogERC( SCH_EDIT_FRAME* aCaller )
+{
+ // This is a modeless dialog, so new it rather than instantiating on stack.
+ DIALOG_ERC* dlg = new DIALOG_ERC( aCaller );
+
+ dlg->Show( true );
+
+ return dlg; // wxDialog is information hiding about DIALOG_ERC.
+}