001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.conflict.pair; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.GridBagLayout; 007import java.util.List; 008 009import javax.swing.AbstractAction; 010import javax.swing.JButton; 011import javax.swing.JComponent; 012import javax.swing.JLabel; 013import javax.swing.JPanel; 014 015import org.openstreetmap.josm.tools.GBC; 016 017/** 018 * A panel used as tab in the merge dialog. 019 * Contains helper methods for creating merge dialog columns. 020 * 021 * @author Michael Zangl 022 * @since 12044 023 */ 024public abstract class AbstractMergePanel extends JPanel { 025 026 /** 027 * A helper class to add a row to the layout. Each row has 6 columns. 028 * @author Michael Zangl 029 */ 030 protected static class MergeRow { 031 protected int marginTop = 5; 032 033 public MergeRow() { 034 // allow access from subclasses 035 } 036 037 protected JComponent rowTitle() { 038 return null; 039 } 040 041 protected JComponent mineField() { 042 return null; 043 } 044 045 protected JComponent mineButton() { 046 return null; 047 } 048 049 protected JComponent merged() { 050 return null; 051 } 052 053 protected JComponent theirsButton() { 054 return null; 055 } 056 057 protected JComponent theirsField() { 058 return null; 059 } 060 061 void addTo(AbstractMergePanel panel) { 062 JComponent[] buttons = getColumns(); 063 for (int columnIndex = 0; columnIndex < buttons.length; columnIndex++) { 064 if (buttons[columnIndex] != null) { 065 GBC constraints = GBC.std(columnIndex, panel.currentRow); 066 addConstraints(constraints, columnIndex); 067 panel.add(buttons[columnIndex], constraints); 068 } 069 } 070 panel.currentRow++; 071 } 072 073 protected JComponent[] getColumns() { 074 return new JComponent[] { 075 rowTitle(), 076 mineField(), 077 mineButton(), 078 merged(), 079 theirsButton(), 080 theirsField() 081 }; 082 } 083 084 protected void addConstraints(GBC constraints, int columnIndex) { 085 constraints.anchor(GBC.CENTER); 086 constraints.fill = GBC.BOTH; 087 constraints.weight(0, 0); 088 constraints.insets(3, marginTop, 3, 0); 089 if (columnIndex == 1 || columnIndex == 3 || columnIndex == 5) { 090 // resize those rows 091 constraints.weightx = 1; 092 } 093 } 094 } 095 096 /** 097 * A row that does not contain the merge buttons. Fields in this row fill both the button and filed area. 098 */ 099 protected static class MergeRowWithoutButton extends MergeRow { 100 @Override 101 protected JComponent[] getColumns() { 102 return new JComponent[] { 103 rowTitle(), 104 mineField(), // width: 2 105 null, 106 merged(), 107 theirsField(), // width: 2 108 null, 109 }; 110 } 111 112 @Override 113 protected void addConstraints(GBC constraints, int columnIndex) { 114 super.addConstraints(constraints, columnIndex); 115 116 if (columnIndex == 1 || columnIndex == 4) { 117 constraints.gridwidth = 2; 118 } 119 } 120 } 121 122 /** 123 * The title for the rows (mine, merged, theirs) 124 */ 125 protected static class TitleRow extends MergeRow { 126 public TitleRow() { 127 // allow access from subclasses 128 } 129 130 @Override 131 protected JComponent mineField() { 132 JLabel label = new JLabel(tr("My version (local dataset)")); 133 label.setToolTipText(tr("Properties in my dataset, i.e. the local dataset")); 134 label.setHorizontalAlignment(JLabel.CENTER); 135 return label; 136 } 137 138 @Override 139 protected JComponent merged() { 140 JLabel label = new JLabel(tr("Merged version")); 141 label.setToolTipText( 142 tr("Properties in the merged element. They will replace properties in my elements when merge decisions are applied.")); 143 label.setHorizontalAlignment(JLabel.CENTER); 144 return label; 145 } 146 147 @Override 148 protected JComponent theirsField() { 149 JLabel label = new JLabel(tr("Their version (server dataset)")); 150 label.setToolTipText(tr("Properties in their dataset, i.e. the server dataset")); 151 label.setHorizontalAlignment(JLabel.CENTER); 152 return label; 153 } 154 } 155 156 /** 157 * Add the undecide button to the middle of the merged row. 158 */ 159 protected abstract static class AbstractUndecideRow extends AbstractMergePanel.MergeRow { 160 @Override 161 protected JComponent merged() { 162 AbstractAction actUndecide = createAction(); 163 JButton button = new JButton(actUndecide); 164 button.setName(getButtonName()); 165 return button; 166 } 167 168 protected abstract AbstractAction createAction(); 169 170 protected abstract String getButtonName(); 171 172 @Override 173 protected void addConstraints(GBC constraints, int columnIndex) { 174 super.addConstraints(constraints, columnIndex); 175 constraints.fill(GBC.NONE); 176 } 177 } 178 179 /** 180 * The current row counter. Used when adding new rows. 181 */ 182 protected int currentRow; 183 184 /** 185 * Create a new merge panel. 186 */ 187 public AbstractMergePanel() { 188 super(new GridBagLayout()); 189 } 190 191 /** 192 * Add the rows to this component. 193 * This needs to be called in the constructor of the child class. That way, all it's fields are initialized. 194 */ 195 protected void buildRows() { 196 getRows().forEach(row -> row.addTo(this)); 197 } 198 199 /** 200 * Gets the rows. 201 * @return A list of rows that should be displayed in this dialog. 202 */ 203 protected abstract List<? extends MergeRow> getRows(); 204 205}