66AUTO_MODE loadAutoResolutionFile( std::map<wxString, KICAD_DIFF::ITEM_RES>& aOut )
70 if( !wxGetEnv( wxT(
"KICAD_MERGETOOL_AUTO" ), &
path ) ||
path.IsEmpty() )
71 return AUTO_MODE::NOT_SET;
73 wxFFile file(
path, wxT(
"rb" ) );
76 if( !file.IsOpened() || !file.ReadAll( &contents, wxConvUTF8 ) )
79 wxT(
"KICAD_MERGETOOL_AUTO points at unreadable path '%s'" ),
path );
80 return AUTO_MODE::LOAD_FAILED;
85 std::string( contents.utf8_str().data(), contents.utf8_str().length() ) );
90 wxT(
"KICAD_MERGETOOL_AUTO parse failed (status=%d, context=%s)" ),
92 return AUTO_MODE::LOAD_FAILED;
96 return AUTO_MODE::LOADED;
114 m_canvas = new WIDGET_DIFF_CANVAS( m_panelResolution );
115 m_canvas->SetMinSize( wxSize( -1, 200 ) );
119 const size_t insertAt = std::min<size_t>( 1, resolutionSizer->GetItemCount() );
120 resolutionSizer->Insert( insertAt, m_canvas,
121 wxSizerFlags( 1 ).Expand().Border( wxALL, 4 ) );
122 m_panelResolution->Layout();
129 m_labelDetail->SetLabel( _(
"No conflicts to resolve." ) );
130 m_sdbSizerApply->Enable( true );
134 m_labelDetail->SetLabel( wxString::Format( _(
"%zu conflict(s) require resolution." ),
135 m_conflictActionIndex.size() ) );
151 std::map<wxString, KICAD_DIFF::ITEM_RES> autoResolutions;
153 switch( loadAutoResolutionFile( autoResolutions ) )
155 case AUTO_MODE::NOT_SET:
158 case AUTO_MODE::LOAD_FAILED:
160 wxT(
"KICAD_MERGETOOL_AUTO load failed; closing dialog as cancelled" ) );
161 CallAfter( [
this]() { EndModal( wxID_CANCEL ); } );
164 case AUTO_MODE::LOADED:
174 wxT(
"KICAD_MERGETOOL_AUTO missing resolution for %s" ),
176 CallAfter( [
this]() { EndModal( wxID_CANCEL ); } );
181 CallAfter( [
this]() { EndModal( wxID_APPLY ); } );
183 wxT(
"KICAD_MERGETOOL_AUTO applied %zu auto-resolutions" ),
196 EndModal( wxID_CANCEL );
202 EndModal( wxID_CANCEL );
212 const std::vector<KIID_PATH> stillUnresolved =
215 if( !stillUnresolved.empty() )
217 wxMessageBox( wxString::Format(
_(
"%zu conflict(s) still need a resolution. "
218 "Pick Ours, Theirs, or Ancestor for each one." ),
219 stillUnresolved.size() ),
220 _(
"Resolve Merge Conflicts" ),
221 wxOK | wxICON_INFORMATION,
this );
225 m_plan.unresolved.clear();
226 EndModal( wxID_APPLY );
271 const std::map<KIID_PATH, BOX2I>* primaryBBoxes =
nullptr;
285 primaryBBoxes = &
m_context.ancestorBBoxes;
289 static const std::map<KIID_PATH, BOX2I> emptyBBoxMap;
299 const std::optional<BOX2I> resolved =
302 primaryBBoxes ? *primaryBBoxes : emptyBBoxMap,
306 if( resolved.has_value() )
308 conflictBBox = *resolved;
311 shape.
bbox = conflictBBox;
312 shape.
color = highlightColor();
323 const std::optional<KIID_PATH> highlight =
325 ? std::optional<KIID_PATH>(
329 m_canvas->SetScene( std::move( scene ) );
330 m_canvas->HighlightChange( highlight );
336 BOX2I focus = conflictBBox;
363 m_labelDetail->SetLabel(
_(
"Select a conflict on the left to see details." ) );
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
wxRadioButton * m_radioTheirs
wxRadioButton * m_radioAncestor
wxRadioButton * m_radioOurs
wxStaticText * m_labelDetail
wxListBox * m_listConflicts
DIALOG_KICAD_MERGE_3WAY_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Resolve Merge Conflicts"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(950, 700), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
wxTextCtrl * m_textDetail
wxPanel * m_panelResolution
void OnConflictSelected(wxCommandEvent &aEvent) override
DIALOG_KICAD_MERGE_3WAY(wxWindow *aParent, const KICAD_DIFF::MERGE_PLAN &aPlan, CONFLICT_CONTEXT aContext={})
void OnApply(wxCommandEvent &aEvent) override
void OnCancel(wxCommandEvent &aEvent) override
void rebuildCanvas()
Rebuild the canvas scene from the current side (per radio) and the active conflict's bbox.
void OnClose(wxCloseEvent &aEvent) override
WIDGET_DIFF_CANVAS * m_canvas
GAL-backed conflict viewer injected into the resolution panel.
KICAD_DIFF::MERGE_PLAN m_plan
int m_currentConflict
Currently-displayed conflict (index into m_conflictActionIndex), -1 if none.
CONFLICT_CONTEXT m_context
void showConflict(int aIndex)
Update the detail panel for the selected conflict.
void buildList()
Populate the conflict list from the plan's unresolved items.
SIDE
Which side's geometry the canvas should currently display.
void OnResolutionChanged(wxCommandEvent &aEvent) override
std::vector< std::size_t > m_conflictActionIndex
Indices into m_plan.actions matching the order of m_listConflicts.
A color representation with 4 components: red, green, blue, alpha.
wxString AsString() const
const wxChar *const traceDiffMerge
Flag to enable diff/merge engine and renderer debugging output.
wxString BuildConflictDetailText(const ITEM_RESOLUTION &aResolution)
Build the human-readable detail text shown in the merge dialog's resolution panel for a given ITEM_RE...
AUTO_RESOLUTION_PARSE_RESULT ParseAutoResolutionJson(const std::string &aJsonContent)
Parse a KICAD_MERGETOOL_AUTO-format JSON object mapping item IDs (KIID_PATH strings) to ITEM_RES spel...
@ OK
parsed cleanly; resolutions is populated
std::vector< CONFLICT_LIST_ENTRY > BuildConflictList(const MERGE_PLAN &aPlan)
std::optional< BOX2I > ResolveConflictBBox(const KIID_PATH &aId, const std::map< KIID_PATH, BOX2I > &aPrimary, const std::map< KIID_PATH, BOX2I > &aOurs, const std::map< KIID_PATH, BOX2I > &aTheirs, const std::map< KIID_PATH, BOX2I > &aAncestor)
Resolve the best bounding box for a conflicted item across the three sides of a 3-way merge.
APPLY_AUTO_RESOLUTIONS_RESULT ApplyAutoResolutions(MERGE_PLAN &aPlan, const std::vector< std::size_t > &aConflictActionIndices, const std::map< wxString, ITEM_RES > &aResolutions)
Apply a parsed auto-resolution map to a MERGE_PLAN's conflicts.
void ExpandBBoxToGeometry(DIFF_SCENE &aScene)
Grow the scene's documentBBox to also include the extent of any background geometry.
std::vector< KIID_PATH > CollectUnresolvedConflicts(const MERGE_PLAN &aPlan, const std::vector< std::size_t > &aConflictActionIndices)
Return the subset of conflict actions whose kind is NOT one of the concrete TAKE_OURS / TAKE_THEIRS /...
Phase 8 context for the conflict canvas.
APPLY_AUTO_RESOLUTIONS_STATUS status
KIID_PATH firstMissingId
Set only when status == PARTIAL AND the partial result was caused by a missing entry in the auto-reso...
Result of ParseAutoResolutionJson.
AUTO_RESOLUTION_STATUS status
std::map< wxString, ITEM_RES > resolutions
Build the list of conflict-action indices the dialog walks (i.e.
DOCUMENT_GEOMETRY referenceGeometry
Background geometry from the two source documents.
std::vector< SCENE_SHAPE > conflictShapes
Result of planning a 3-way merge.
Shared rendering model consumed by both the GAL renderer (interactive widget) and the plotter rendere...
KIID_PATH changeId
Stable identifier of the ITEM_CHANGE that produced this shape.
wxLogTrace helper definitions.