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;
118 m_canvas->SetMinSize( wxSize( -1, 200 ) );
122 const size_t insertAt = std::min<size_t>( 1, resolutionSizer->GetItemCount() );
123 resolutionSizer->Insert( insertAt,
m_canvas,
124 wxSizerFlags( 1 ).Expand().Border( wxALL, 4 ) );
159 std::map<wxString, KICAD_DIFF::ITEM_RES> autoResolutions;
161 switch( loadAutoResolutionFile( autoResolutions ) )
163 case AUTO_MODE::NOT_SET:
166 case AUTO_MODE::LOAD_FAILED:
168 wxT(
"KICAD_MERGETOOL_AUTO load failed; closing dialog as cancelled" ) );
169 CallAfter( [
this]() { EndModal( wxID_CANCEL ); } );
172 case AUTO_MODE::LOADED:
182 wxT(
"KICAD_MERGETOOL_AUTO missing resolution for %s" ),
184 CallAfter( [
this]() { EndModal( wxID_CANCEL ); } );
189 CallAfter( [
this]() { EndModal( wxID_APPLY ); } );
191 wxT(
"KICAD_MERGETOOL_AUTO applied %zu auto-resolutions" ),
204 EndModal( wxID_CANCEL );
210 EndModal( wxID_CANCEL );
217 const std::vector<KIID_PATH> stillUnresolved =
220 if( !stillUnresolved.empty() )
222 wxMessageBox( wxString::Format( wxPLURAL(
"%zu conflict still needs a resolution. "
223 "Pick Ours, Theirs, or Ancestor for each one.",
224 "%zu conflicts still need a resolution. "
225 "Pick Ours, Theirs, or Ancestor for each one.",
226 stillUnresolved.size() ),
227 stillUnresolved.size() ),
228 _(
"Resolve Merge Conflicts" ),
229 wxOK | wxICON_INFORMATION,
this );
233 m_plan.unresolved.clear();
234 EndModal( wxID_APPLY );
287 const std::map<KIID_PATH, BOX2I>* primaryBBoxes =
nullptr;
301 primaryBBoxes = &
m_context.ancestorBBoxes;
305 static const std::map<KIID_PATH, BOX2I> emptyBBoxMap;
315 const std::optional<BOX2I> resolved =
318 primaryBBoxes ? *primaryBBoxes : emptyBBoxMap,
322 if( resolved.has_value() )
324 conflictBBox = *resolved;
327 shape.
bbox = conflictBBox;
328 shape.
color = highlightColor();
339 std::optional<KIID_PATH> highlight;
344 m_canvas->SetScene( std::move( scene ) );
351 m_canvas->HighlightChange( highlight );
357 BOX2I focus = conflictBBox;
368 wxString named =
m_context.describeItem( aId );
370 if( !named.IsEmpty() )
400 m_labelDetail->SetLabel(
_(
"Select a conflict on the left to see details." ) );
412 m_radioUnresolved->SetLabel( offersMerge ?
_(
"Merge both changes" ) :
_(
"Not decided yet" ) );
416 switch( action.
kind )
429 case SIDE::OURS: shown =
_(
"showing your version" );
break;
430 case SIDE::THEIRS: shown =
_(
"showing their version" );
break;
441 +
_(
"\n\nBoth sides changed this item, and their edits are combined.\n"
442 "Where both changed the same thing, your version is kept.\n"
443 "Pick a side to take that version whole instead." ) );
447 m_textDetail->SetValue(
_(
"Pick Ours, Theirs, or Ancestor to preview and keep that version." ) );
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
wxButton * m_sdbSizerApply
wxRadioButton * m_radioTheirs
wxRadioButton * m_radioAncestor
wxStaticText * m_labelIntro
wxRadioButton * m_radioUnresolved
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
SIDE activeSide() const
The side the canvas previews.
DIALOG_KICAD_MERGE_3WAY(wxWindow *aParent, const KICAD_DIFF::MERGE_PLAN &aPlan, CONFLICT_CONTEXT aContext={})
void OnApply(wxCommandEvent &aEvent) override
wxString describe(const KIID_PATH &aId, const wxString &aFallback) const
The item's name from the editor, or aFallback when there is none.
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 version the canvas should currently display.
std::vector< bool > m_hasMergedEdit
True where the engine combined both sides' edits, in the order of m_conflictActionIndex.
void OnResolutionChanged(wxCommandEvent &aEvent) override
std::vector< std::size_t > m_conflictActionIndex
Indices into m_plan.actions matching the order of m_listConflicts.
void OptOut(wxWindow *aWindow)
Opt out of control state saving.
A color representation with 4 components: red, green, blue, alpha.
wxString AsString() const
static bool empty(const wxTextEntryBase *aCtrl)
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 conflict actions that still have no decision.
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: the positions in plan....
Diff colors with defaults for light backgrounds.
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.