summaryrefslogtreecommitdiff
path: root/pcbnew/dialogs/dialog_drc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pcbnew/dialogs/dialog_drc.cpp')
-rw-r--r--pcbnew/dialogs/dialog_drc.cpp647
1 files changed, 647 insertions, 0 deletions
diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp
new file mode 100644
index 0000000..2c3725d
--- /dev/null
+++ b/pcbnew/dialogs/dialog_drc.cpp
@@ -0,0 +1,647 @@
+/**
+ * @file dialog_drc.cpp
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 2009 Dick Hollenbeck, dick@softplc.com
+ * Copyright (C) 2004-2016 KiCad Developers, see change_log.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 <fctsys.h>
+#include <confirm.h>
+#include <wildcards_and_files_ext.h>
+#include <pgm_base.h>
+#include <dialog_drc.h>
+#include <wxPcbStruct.h>
+#include <base_units.h>
+#include <class_board_design_settings.h>
+#include <class_draw_panel_gal.h>
+
+/* class DIALOG_DRC_CONTROL: a dialog to set DRC parameters (clearance, min cooper size)
+ * and run DRC tests
+ */
+
+DIALOG_DRC_CONTROL::DIALOG_DRC_CONTROL( DRC* aTester, PCB_EDIT_FRAME* parent ) :
+ DIALOG_DRC_CONTROL_BASE( parent )
+{
+ m_tester = aTester;
+ m_Parent = parent;
+ m_currentBoard = m_Parent->GetBoard();
+ m_BrdSettings = m_Parent->GetBoard()->GetDesignSettings();
+
+ InitValues();
+
+ FixOSXCancelButtonIssue();
+
+ // Now all widgets have the size fixed, call FinishDialogSettings
+ FinishDialogSettings();
+}
+
+
+void DIALOG_DRC_CONTROL::OnActivateDlg( wxActivateEvent& event )
+{
+ if( m_currentBoard != m_Parent->GetBoard() )
+ {
+ // If m_currentBoard is not the current parent board,
+ // (for instance because a new board was loaded),
+ // close the dialog, because many pointers are now invalid
+ // in lists
+ SetReturnCode( wxID_CANCEL );
+ Close();
+ m_tester->DestroyDialog( wxID_CANCEL );
+ return;
+ }
+
+ // updating data which can be modified outside the dialog (DRC parameters, units ...)
+ // because the dialog is not modal
+ m_BrdSettings = m_Parent->GetBoard()->GetDesignSettings();
+ DisplayDRCValues();
+}
+
+
+void DIALOG_DRC_CONTROL::DisplayDRCValues()
+{
+ m_TrackMinWidthUnit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
+ m_ViaMinUnit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
+ m_MicroViaMinUnit->SetLabel(GetAbbreviatedUnitsLabel( g_UserUnit ) );
+
+ PutValueInLocalUnits( *m_SetTrackMinWidthCtrl, m_BrdSettings.m_TrackMinWidth );
+ PutValueInLocalUnits( *m_SetViaMinSizeCtrl, m_BrdSettings.m_ViasMinSize );
+ PutValueInLocalUnits( *m_SetMicroViakMinSizeCtrl, m_BrdSettings.m_MicroViasMinSize );
+}
+
+
+void DIALOG_DRC_CONTROL::InitValues()
+{
+ // Connect events and objects
+ m_ClearanceListBox->Connect( ID_CLEARANCE_LIST, wxEVT_LEFT_DCLICK,
+ wxMouseEventHandler(
+ DIALOG_DRC_CONTROL::OnLeftDClickClearance ), NULL, this );
+ m_ClearanceListBox->Connect( ID_CLEARANCE_LIST, wxEVT_RIGHT_UP,
+ wxMouseEventHandler(
+ DIALOG_DRC_CONTROL::OnRightUpClearance ), NULL, this );
+ m_UnconnectedListBox->Connect( ID_UNCONNECTED_LIST, wxEVT_LEFT_DCLICK,
+ wxMouseEventHandler( DIALOG_DRC_CONTROL::
+ OnLeftDClickUnconnected ), NULL, this );
+ m_UnconnectedListBox->Connect( ID_UNCONNECTED_LIST, wxEVT_RIGHT_UP,
+ wxMouseEventHandler(
+ DIALOG_DRC_CONTROL::OnRightUpUnconnected ), NULL, this );
+
+ m_DeleteCurrentMarkerButton->Enable( false );
+
+ DisplayDRCValues();
+
+ // Set the initial "enabled" status of the browse button and the text
+ // field for report name
+ wxCommandEvent junk;
+ OnReportCheckBoxClicked( junk );
+
+ Layout(); // adding the units above expanded Clearance text, now resize.
+
+ SetFocus();
+}
+
+/* accept DRC parameters (min clearance value and min sizes
+*/
+void DIALOG_DRC_CONTROL::SetDrcParmeters( )
+{
+ m_BrdSettings.m_TrackMinWidth = ValueFromTextCtrl( *m_SetTrackMinWidthCtrl );
+ m_BrdSettings.m_ViasMinSize = ValueFromTextCtrl( *m_SetViaMinSizeCtrl );
+ m_BrdSettings.m_MicroViasMinSize = ValueFromTextCtrl( *m_SetMicroViakMinSizeCtrl );
+
+ m_Parent->GetBoard()->SetDesignSettings( m_BrdSettings );
+}
+
+
+void DIALOG_DRC_CONTROL::SetRptSettings( bool aEnable, const wxString& aFileName )
+{
+ m_RptFilenameCtrl->Enable( aEnable );
+ m_BrowseButton->Enable( aEnable );
+ m_CreateRptCtrl->SetValue( aEnable );
+ m_RptFilenameCtrl->SetValue( aFileName );
+}
+
+void DIALOG_DRC_CONTROL::GetRptSettings( bool* aEnable, wxString& aFileName )
+{
+ *aEnable = m_CreateRptCtrl->GetValue();
+ aFileName = m_RptFilenameCtrl->GetValue();
+}
+
+void DIALOG_DRC_CONTROL::OnStartdrcClick( wxCommandEvent& event )
+{
+ wxString reportName;
+
+ bool make_report = m_CreateRptCtrl->IsChecked();
+
+ if( make_report ) // Create a rpt file
+ {
+ reportName = m_RptFilenameCtrl->GetValue();
+
+ if( reportName.IsEmpty() )
+ {
+ wxCommandEvent dummy;
+ OnButtonBrowseRptFileClick( dummy );
+ }
+
+ if( !reportName.IsEmpty() )
+ reportName = makeValidFileNameReport();
+ }
+
+ SetDrcParmeters();
+ m_tester->SetSettings( true, // Pad to pad DRC test enabled
+ true, // unconnected pads DRC test enabled
+ true, // DRC test for zones enabled
+ true, // DRC test for keepout areas enabled
+ reportName, make_report );
+
+ DelDRCMarkers();
+
+ wxBeginBusyCursor();
+
+ // run all the tests, with no UI at this time.
+ m_Messages->Clear();
+ wxSafeYield(); // Allows time slice to refresh the m_Messages window
+ m_Parent->GetBoard()->m_Status_Pcb = 0; // Force full connectivity and ratsnest recalculations
+ m_tester->RunTests(m_Messages);
+ m_Notebook->ChangeSelection( 0 ); // display the 1at tab "...Markers ..."
+
+
+ // Generate the report
+ if( !reportName.IsEmpty() )
+ {
+ if( writeReport( reportName ) )
+ {
+ wxString msg;
+ msg.Printf( _( "Report file \"%s\" created" ), GetChars( reportName ) );
+
+ wxString caption( _( "Disk File Report Completed" ) );
+ wxMessageDialog popupWindow( this, msg, caption );
+ popupWindow.ShowModal();
+ }
+ else
+ DisplayError( this, wxString::Format( _( "Unable to create report file '%s' "),
+ GetChars( reportName ) ) );
+ }
+
+ wxEndBusyCursor();
+
+ RedrawDrawPanel();
+}
+
+
+void DIALOG_DRC_CONTROL::OnDeleteAllClick( wxCommandEvent& event )
+{
+ DelDRCMarkers();
+ RedrawDrawPanel();
+}
+
+
+void DIALOG_DRC_CONTROL::OnListUnconnectedClick( wxCommandEvent& event )
+{
+ wxString reportName;
+
+ bool make_report = m_CreateRptCtrl->IsChecked();
+
+ if( make_report ) // Create a file rpt
+ {
+ reportName = m_RptFilenameCtrl->GetValue();
+
+ if( reportName.IsEmpty() )
+ {
+ wxCommandEvent junk;
+ OnButtonBrowseRptFileClick( junk );
+ }
+
+ if( !reportName.IsEmpty() )
+ reportName = makeValidFileNameReport();
+ }
+
+ SetDrcParmeters();
+
+ m_tester->SetSettings( true, // Pad to pad DRC test enabled
+ true, // unconnected pads DRC test enabled
+ true, // DRC test for zones enabled
+ true, // DRC test for keepout areas enabled
+ reportName, make_report );
+
+ DelDRCMarkers();
+
+ wxBeginBusyCursor();
+
+ m_Messages->Clear();
+ m_tester->ListUnconnectedPads();
+
+ m_Notebook->ChangeSelection( 1 ); // display the 2nd tab "Unconnected..."
+
+ // Generate the report
+ if( !reportName.IsEmpty() )
+ {
+ if( writeReport( reportName ) )
+ {
+ wxString msg;
+ msg.Printf( _( "Report file \"%s\" created" ), GetChars( reportName ) );
+ wxString caption( _( "Disk File Report Completed" ) );
+ wxMessageDialog popupWindow( this, msg, caption );
+ popupWindow.ShowModal();
+ }
+ else
+ DisplayError( this, wxString::Format( _( "Unable to create report file '%s' "),
+ GetChars( reportName ) ) );
+ }
+
+ wxEndBusyCursor();
+
+ /* there is currently nothing visible on the DrawPanel for unconnected pads
+ * RedrawDrawPanel();
+ */
+}
+
+
+void DIALOG_DRC_CONTROL::OnButtonBrowseRptFileClick( wxCommandEvent& event )
+{
+ wxFileName fn = m_Parent->GetBoard()->GetFileName();
+ fn.SetExt( ReportFileExtension );
+ wxString prj_path = Prj().GetProjectPath();
+
+ wxFileDialog dlg( this, _( "Save DRC Report File" ), prj_path,
+ fn.GetFullName(), ReportFileWildcard,
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
+
+ if( dlg.ShowModal() == wxID_CANCEL )
+ return;
+
+ m_RptFilenameCtrl->SetValue( dlg.GetPath() );
+}
+
+
+void DIALOG_DRC_CONTROL::OnOkClick( wxCommandEvent& event )
+{
+ SetReturnCode( wxID_OK );
+ SetDrcParmeters();
+
+ m_tester->DestroyDialog( wxID_OK );
+}
+
+
+void DIALOG_DRC_CONTROL::OnCancelClick( wxCommandEvent& event )
+{
+ SetReturnCode( wxID_CANCEL );
+
+ m_tester->DestroyDialog( wxID_CANCEL );
+}
+
+
+/*!
+ * wxEVT_COMMAND_CHECKBOX_CLICKED event handler for ID_CHECKBOX1
+ */
+
+void DIALOG_DRC_CONTROL::OnReportCheckBoxClicked( wxCommandEvent& event )
+{
+ m_RptFilenameCtrl->Enable( m_CreateRptCtrl->IsChecked() );
+ m_BrowseButton->Enable( m_CreateRptCtrl->IsChecked() );
+}
+
+
+void DIALOG_DRC_CONTROL::OnLeftDClickClearance( wxMouseEvent& event )
+{
+ event.Skip();
+
+ // I am assuming that the double click actually changed the selected item.
+ // please verify this.
+ int selection = m_ClearanceListBox->GetSelection();
+
+ if( selection != wxNOT_FOUND )
+ {
+ // Find the selected MARKER in the PCB, position cursor there.
+ // Then close the dialog.
+ const DRC_ITEM* item = m_ClearanceListBox->GetItem( selection );
+
+ if( item )
+ {
+ m_Parent->CursorGoto( item->GetPointA() );
+ m_Parent->GetGalCanvas()->GetView()->SetCenter( VECTOR2D( item->GetPointA() ) );
+
+ // turn control over to m_Parent, hide this DIALOG_DRC_CONTROL window,
+ // no destruction so we can preserve listbox cursor
+ Show( false );
+
+ // We do not want the clarification popup window.
+ // when releasing the left button in the main window
+ m_Parent->SkipNextLeftButtonReleaseEvent();
+ }
+ }
+}
+
+
+void DIALOG_DRC_CONTROL::OnPopupMenu( wxCommandEvent& event )
+{
+ int source = event.GetId();
+
+ const DRC_ITEM* item = 0;
+ wxPoint pos;
+
+ int selection;
+
+ switch( source )
+ {
+ case ID_POPUP_UNCONNECTED_A:
+ selection = m_UnconnectedListBox->GetSelection();
+ item = m_UnconnectedListBox->GetItem( selection );
+ pos = item->GetPointA();
+ break;
+
+ case ID_POPUP_UNCONNECTED_B:
+ selection = m_UnconnectedListBox->GetSelection();
+ item = m_UnconnectedListBox->GetItem( selection );
+ pos = item->GetPointB();
+ break;
+
+ case ID_POPUP_MARKERS_A:
+ selection = m_ClearanceListBox->GetSelection();
+ item = m_ClearanceListBox->GetItem( selection );
+ pos = item->GetPointA();
+ break;
+
+ case ID_POPUP_MARKERS_B:
+ selection = m_ClearanceListBox->GetSelection();
+ item = m_ClearanceListBox->GetItem( selection );
+ pos = item->GetPointB();
+ break;
+ }
+
+ if( item )
+ {
+ m_Parent->CursorGoto( pos );
+ m_Parent->GetGalCanvas()->GetView()->SetCenter( VECTOR2D( item->GetPointA() ) );
+
+ Show( false );
+ }
+}
+
+
+void DIALOG_DRC_CONTROL::OnRightUpUnconnected( wxMouseEvent& event )
+{
+ event.Skip();
+
+ // popup menu to go to either of the items listed in the DRC_ITEM.
+
+ int selection = m_UnconnectedListBox->GetSelection();
+
+ if( selection != wxNOT_FOUND )
+ {
+ wxMenu menu;
+ wxMenuItem* mItem;
+ const DRC_ITEM* dItem = m_UnconnectedListBox->GetItem( selection );
+
+ mItem = new wxMenuItem( &menu, ID_POPUP_UNCONNECTED_A, dItem->GetTextA() );
+ menu.Append( mItem );
+
+ if( dItem->HasSecondItem() )
+ {
+ mItem = new wxMenuItem( &menu, ID_POPUP_UNCONNECTED_B, dItem->GetTextB() );
+ menu.Append( mItem );
+ }
+
+ PopupMenu( &menu );
+ }
+}
+
+
+void DIALOG_DRC_CONTROL::OnRightUpClearance( wxMouseEvent& event )
+{
+ event.Skip();
+
+ // popup menu to go to either of the items listed in the DRC_ITEM.
+
+ int selection = m_ClearanceListBox->GetSelection();
+
+ if( selection != wxNOT_FOUND )
+ {
+ wxMenu menu;
+ wxMenuItem* mItem;
+ const DRC_ITEM* dItem = m_ClearanceListBox->GetItem( selection );
+
+ mItem = new wxMenuItem( &menu, ID_POPUP_MARKERS_A, dItem->GetTextA() );
+ menu.Append( mItem );
+
+ if( dItem->HasSecondItem() )
+ {
+ mItem = new wxMenuItem( &menu, ID_POPUP_MARKERS_B, dItem->GetTextB() );
+ menu.Append( mItem );
+ }
+
+ PopupMenu( &menu );
+ }
+}
+
+
+void DIALOG_DRC_CONTROL::OnLeftDClickUnconnected( wxMouseEvent& event )
+{
+ event.Skip();
+
+ // I am assuming that the double click actually changed the selected item.
+ // please verify this.
+ int selection = m_UnconnectedListBox->GetSelection();
+
+ if( selection != wxNOT_FOUND )
+ {
+ // Find the selected DRC_ITEM in the listbox, position cursor there,
+ // at the first of the two pads.
+ // Then hide the dialog.
+ const DRC_ITEM* item = m_UnconnectedListBox->GetItem( selection );
+ if( item )
+ {
+ m_Parent->CursorGoto( item->GetPointA() );
+ m_Parent->GetGalCanvas()->GetView()->SetCenter( VECTOR2D( item->GetPointA() ) );
+
+ Show( false );
+
+ // We do not want the clarification popup window.
+ // when releasing the left button in the main window
+ m_Parent->SkipNextLeftButtonReleaseEvent();
+ }
+ }
+}
+
+/* called when switching from Error list to Unconnected list
+ * To avoid mistakes, the current marker is selection is cleared
+ */
+void DIALOG_DRC_CONTROL::OnChangingMarkerList( wxNotebookEvent& event )
+{
+ m_DeleteCurrentMarkerButton->Enable( false );
+ m_ClearanceListBox->SetSelection( -1 );
+ m_UnconnectedListBox->SetSelection( -1 );
+}
+
+void DIALOG_DRC_CONTROL::OnMarkerSelectionEvent( wxCommandEvent& event )
+{
+ int selection = event.GetSelection();
+
+ if( selection != wxNOT_FOUND )
+ {
+ // until a MARKER is selected, this button is not enabled.
+ m_DeleteCurrentMarkerButton->Enable( true );
+
+ // Find the selected DRC_ITEM in the listbox, position cursor there,
+ // at the first of the two pads.
+ const DRC_ITEM* item = m_ClearanceListBox->GetItem( selection );
+ if( item )
+ {
+ m_Parent->CursorGoto( item->GetPointA(), false );
+ m_Parent->GetGalCanvas()->GetView()->SetCenter( VECTOR2D( item->GetPointA() ) );
+ }
+ }
+
+ event.Skip();
+}
+
+
+void DIALOG_DRC_CONTROL::OnUnconnectedSelectionEvent( wxCommandEvent& event )
+{
+ int selection = event.GetSelection();
+
+ if( selection != wxNOT_FOUND )
+ {
+ // until a MARKER is selected, this button is not enabled.
+ m_DeleteCurrentMarkerButton->Enable( true );
+
+ // Find the selected DRC_ITEM in the listbox, position cursor there,
+ // at the first of the two pads.
+ const DRC_ITEM* item = m_UnconnectedListBox->GetItem( selection );
+ if( item )
+ {
+ m_Parent->CursorGoto( item->GetPointA(), false );
+ m_Parent->GetGalCanvas()->GetView()->SetCenter( VECTOR2D( item->GetPointA() ) );
+ }
+ }
+
+ event.Skip();
+}
+
+
+void DIALOG_DRC_CONTROL::RedrawDrawPanel()
+{
+ m_Parent->GetCanvas()->Refresh();
+}
+
+
+void DIALOG_DRC_CONTROL::DelDRCMarkers()
+{
+ m_Parent->SetCurItem( NULL ); // clear curr item, because it could be a DRC marker
+ m_ClearanceListBox->DeleteAllItems();
+ m_UnconnectedListBox->DeleteAllItems();
+ m_DeleteCurrentMarkerButton->Enable( false );
+}
+
+
+const wxString DIALOG_DRC_CONTROL::makeValidFileNameReport()
+{
+ wxFileName fn = m_RptFilenameCtrl->GetValue();
+
+ if( !fn.HasExt() )
+ {
+ fn.SetExt( ReportFileExtension );
+ m_RptFilenameCtrl->SetValue( fn.GetFullPath() );
+ }
+
+ // Ensure it is an absolute filename. if it is given relative
+ // it will be made relative to the project
+ if( !fn.IsAbsolute() )
+ {
+ wxString prj_path = Prj().GetProjectPath();
+ fn.MakeAbsolute( prj_path );
+ }
+
+ return fn.GetFullPath();
+}
+
+
+bool DIALOG_DRC_CONTROL::writeReport( const wxString& aFullFileName )
+{
+ FILE* fp = wxFopen( aFullFileName, wxT( "w" ) );
+
+ if( fp == NULL )
+ return false;
+
+ int count;
+
+ fprintf( fp, "** Drc report for %s **\n",
+ TO_UTF8( m_Parent->GetBoard()->GetFileName() ) );
+
+ wxDateTime now = wxDateTime::Now();
+
+ fprintf( fp, "** Created on %s **\n", TO_UTF8( now.Format( wxT( "%F %T" ) ) ) );
+
+ count = m_ClearanceListBox->GetItemCount();
+
+ fprintf( fp, "\n** Found %d DRC errors **\n", count );
+
+ for( int i = 0; i<count; ++i )
+ fprintf( fp, "%s", TO_UTF8( m_ClearanceListBox->GetItem( i )->ShowReport()) );
+
+ count = m_UnconnectedListBox->GetItemCount();
+
+ fprintf( fp, "\n** Found %d unconnected pads **\n", count );
+
+ for( int i = 0; i<count; ++i )
+ fprintf( fp, "%s", TO_UTF8( m_UnconnectedListBox->GetItem( i )->ShowReport() ) );
+
+ fprintf( fp, "\n** End of Report **\n" );
+
+ fclose( fp );
+
+ return true;
+}
+
+
+void DIALOG_DRC_CONTROL::OnDeleteOneClick( wxCommandEvent& event )
+{
+ int selectedIndex;
+ int curTab = m_Notebook->GetSelection();
+
+ if( curTab == 0 )
+ {
+ selectedIndex = m_ClearanceListBox->GetSelection();
+
+ if( selectedIndex != wxNOT_FOUND )
+ {
+ m_ClearanceListBox->DeleteItem( selectedIndex );
+
+ // redraw the pcb
+ RedrawDrawPanel();
+ }
+ }
+ else if( curTab == 1 )
+ {
+ selectedIndex = m_UnconnectedListBox->GetSelection();
+
+ if( selectedIndex != wxNOT_FOUND )
+ {
+ m_UnconnectedListBox->DeleteItem( selectedIndex );
+
+ /* these unconnected DRC_ITEMs are not currently visible on the pcb
+ * RedrawDrawPanel();
+ */
+ }
+ }
+}